home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1993 / Internet Info CD-ROM (Walnut Creek) (1993).iso / networking / news / nntp / nntp.isc.shar < prev    next >
Encoding:
Text File  |  1991-03-26  |  67.8 KB  |  2,794 lines

  1. The following shar contains new versions of files that add compatibility with
  2. ISC 2.2 with TCP for the NNTP server. This is an UNOFFICAL patch. Please
  3. define LAI_TCP in common/conf.h to make use of these modifications. They
  4. will be available on the "archive-server@bcm.tmc.edu" as nntp.isc.shar in 
  5. the public directory.
  6.  
  7. #!/bin/sh
  8. # This is a shell archive, meaning:
  9. # 1. Remove everything above the #! /bin/sh line.
  10. # 2. Save the resulting text in a file.
  11. # 3. Execute the file with /bin/sh (not csh) to create the files:
  12. #    server/timer.c
  13. #    server/subnet.c
  14. #    xmit/nntpxmit.c
  15. #    xmit/remote.c
  16. #    xfer/nntpxfer.c
  17. # This archive created: Tue Mar 26 09:40:27 1991
  18. :
  19. export PATH; PATH=/bin:$PATH
  20. if test -d 'server'
  21. then
  22. echo "Entering directory 'server'"
  23. cd 'server'
  24. echo shar: extracting "'timer.c'" '(4008 characters)'
  25. sed 's/^    X//' << \SHAR_EOF > 'timer.c'
  26.     X/*
  27.     X * Machinery to run routines off timers.
  28.     X */
  29.     X#include "common.h"
  30.     X
  31.     X#ifdef TIMERS
  32.     X#ifndef lint
  33.     Xstatic char rcsid[] =
  34.     X    "@(#) $Header: timer.c,v 1.3 91/03/19 03:02:41 sob Exp $ (NNTP with TIMERS)";
  35.     X#endif
  36.     X#else
  37.     X#ifndef lint
  38.     Xstatic char rcsid[] =
  39.     X    "@(#) $Header: timer.c,v 1.3 91/03/19 03:02:41 sob Exp $ (NNTP without TIMERS)";
  40.     X#endif
  41.     X#endif
  42.     X
  43.     X#ifdef TIMERS
  44.     X#include <sys/time.h>
  45.     X#include "timer.h"
  46.     X#ifdef USG
  47.     X#ifdef LAI_TCP
  48.     X#include <sys/bsdtypes.h>
  49.     X#define BSDSELECT
  50.     X#endif
  51.     X#else
  52.     X#ifndef FD_SETSIZE
  53.     X/* Forward compatability */
  54.     X#define FD_SET(n, p)    ((p)->fds_bits[0] |= (1<<(n)))
  55.     X#define FD_CLR(n, p)    ((p)->fds_bits[0] &= ~(1<<(n)))
  56.     X#define FD_ISSET(n, p)  ((p)->fds_bits[0] & (1<<(n)))
  57.     X#define FD_ZERO(p)      ((p)->fds_bits[0] = 0)
  58.     X#define BSDSELECT
  59.     X#endif
  60.     X#endif
  61.     X/* non-portable */
  62.     X#define BUFFERED_DATA(f) ((f)->_cnt > 0)
  63.     X
  64.     Xstatic long lastsecs;
  65.     X
  66.     X/*
  67.     X * Should be called before first call to timer_sleep()
  68.     X */
  69.     Xvoid
  70.     Xtimer_init(timers, ntimer)
  71.     X    register struct timer *timers;
  72.     X    register int ntimer;
  73.     X{
  74.     X    register int i;
  75.     X    register struct timer *tp;
  76.     X
  77.     X#ifdef SYSLOG
  78.     X    if (ntimer <= 0)
  79.     X        syslog(LOG_ERR,
  80.     X            "timer_init(): configuration error, %d timers\n", ntimer);
  81.     X#endif
  82.     X
  83.     X    /* Reset all timers */
  84.     X    for (i = ntimer, tp = timers; i > 0; --i, ++tp)
  85.     X        tp->left = tp->seconds;
  86.     X
  87.     X    /* Start clock */
  88.     X    lastsecs = time((long *)0);
  89.     X}
  90.     X
  91.     X/*
  92.     X * Sleep until input or next timer needs to be run and then run any
  93.     X * expired timers. Returns true if input is available to be read.
  94.     X */
  95.     Xint
  96.     Xtimer_sleep(timers, ntimer)
  97.     X    register struct timer *timers;
  98.     X    register int ntimer;
  99.     X{
  100.     X    register int i, n;
  101.     X    register struct timer *tp;
  102.     X    register long secs;
  103.     X#ifndef BSDSELECT
  104.     X    long timeout;
  105.     X    long readfds;
  106.     X#else
  107.     X    register struct timeval *timeoutp;
  108.     X    struct timeval timeout;
  109.     X    fd_set readfds;
  110.     X#endif
  111.     X
  112.     X    /* No need to do the select if there are characters in the buffer */
  113.     X    if (BUFFERED_DATA(stdin))
  114.     X        return(1);
  115.     X
  116.     X    /* Length of next timeout is minimum of all "timers" */
  117.     X#ifndef BSDSELECT
  118.     X    timeout = -1;
  119.     X    for (i = ntimer, tp = timers; i > 0; --i, ++tp)
  120.     X        if (tp->left >= 0 &&
  121.     X            (tp->left < timeout || timeout < 0))
  122.     X            timeout = tp->left;
  123.     X
  124.     X    /* If active timeouts (this can easily happen), block until input */
  125.     X    if (timeout < 0)
  126.     X        timeout = 0;
  127.     X#ifdef EXCELAN
  128.     X    readfds = 1<<(fileno(stdin));
  129.     X    timeout = timeout * 1000;     /* timeout needs to be in milliseconds */
  130.     X#endif /* EXCELAN */
  131.     X#else
  132.     X    timeout.tv_sec = -1;
  133.     X    timeout.tv_usec = 0;
  134.     X    for (i = ntimer, tp = timers; i > 0; --i, ++tp)
  135.     X        if (tp->left >= 0 &&
  136.     X            (tp->left < timeout.tv_sec || timeout.tv_sec < 0))
  137.     X            timeout.tv_sec = tp->left;
  138.     X
  139.     X    /* If active timeouts (this can easily happen), block until input */
  140.     X    if (timeout.tv_sec < 0)
  141.     X        timeoutp = 0;
  142.     X    else
  143.     X        timeoutp = &timeout;
  144.     X
  145.     X    /* Do select */
  146.     X    FD_ZERO(&readfds);
  147.     X    FD_SET(fileno(stdin), &readfds);
  148.     X#endif /* BSDSELECT */
  149.     X    errno = 0;
  150.     X#ifdef EXCELAN
  151.     X    n = select(fileno(stdin) + 1, &readfds, (long*)0, timeout);
  152.     X#else
  153.     X    n = select(fileno(stdin) + 1,
  154.     X        &readfds, (fd_set*)0, (fd_set*)0, timeoutp);
  155.     X#endif
  156.     X    /* "Interrupted system call" isn't a real error */
  157.     X    if (n < 0 && errno != EINTR) {
  158.     X#ifdef SYSLOG
  159.     X        syslog(LOG_ERR, "%s read select: %m", hostname);
  160.     X#endif
  161.     X        exit(1);
  162.     X    }
  163.     X
  164.     X    /* Calculate off seconds since last time */
  165.     X    secs = time((long *)0) - lastsecs;
  166.     X    if (secs < 0)
  167.     X        secs = 0;
  168.     X
  169.     X    /* Subtract time from "timers" that have time remaining */
  170.     X    for (i = ntimer, tp = timers; i > 0; --i, ++tp)
  171.     X        if (tp->left > 0 && (tp->left -= secs) < 0)
  172.     X            tp->left = 0;
  173.     X
  174.     X    /* Update lastsecs */
  175.     X    lastsecs += secs;
  176.     X
  177.     X    /* If we have input, reset clock on guys that like it that way */
  178.     X    if (n > 0)
  179.     X        for (i = ntimer, tp = timers; i > 0; --i, ++tp)
  180.     X            if (tp->resetoninput)
  181.     X                tp->left = tp->seconds;
  182.     X
  183.     X    /* Process "timers" that have timed out */
  184.     X    for (i = ntimer, tp = timers; i > 0; --i, ++tp) {
  185.     X        if (tp->left == 0) {
  186.     X            (tp->subr)();
  187.     X            /* resetoninput guys only get "reset on input" */
  188.     X            if (tp->resetoninput)
  189.     X                tp->left = -1;
  190.     X            else
  191.     X                tp->left = tp->seconds;
  192.     X        }
  193.     X    }
  194.     X
  195.     X    /* Indicate no input */
  196.     X    if (n <= 0)
  197.     X        return(0);
  198.     X    return(1);
  199.     X    
  200.     X}
  201.     X#endif
  202. SHAR_EOF
  203. if test 4008 -ne "`wc -c < 'timer.c'`"
  204. then
  205.     echo shar: error transmitting "'timer.c'" '(should have been 4008 characters)'
  206. fi
  207. echo shar: extracting "'subnet.c'" '(6645 characters)'
  208. sed 's/^    X//' << \SHAR_EOF > 'subnet.c'
  209.     X#ifndef lint
  210.     Xstatic    char    *sccsid = "@(#)$Header: subnet.c,v 1.9 91/03/19 03:02:30 sob Exp $";
  211.     X#endif
  212.     X
  213.     X#include "../common/conf.h"
  214.     X
  215.     X#ifdef SUBNET
  216.     X
  217.     X#include <sys/types.h>
  218.     X#ifdef LAI_TCP
  219.     X#include <sys/bsdtypes.h>
  220.     X#include <sys/stream.h>
  221.     X#endif
  222.     X#include <sys/socket.h>
  223.     X#include <netinet/in.h>
  224.     X#ifndef NETMASK
  225.     X#include <net/if.h>
  226.     X#endif
  227.     X#ifdef LAI_TCP
  228.     X#include <sys/sioctl.h>
  229.     X#else
  230.     X#include <sys/ioctl.h>
  231.     X#endif
  232.     X/*
  233.     X * The following routines provide a general interface for
  234.     X * subnet support.  Like the library function "inet_netof",
  235.     X * which returns the standard (i.e., non-subnet) network
  236.     X * portion of an internet address, "inet_snetof" returns
  237.     X * the subnetwork portion -- if there is one.  If there
  238.     X * isn't, it returns 0.
  239.     X *
  240.     X * Subnets, under 4.3, are specific to a given set of
  241.     X * machines -- right down to the network interfaces.
  242.     X * Because of this, the function "getifconf" must be
  243.     X * called first.  This routine builds a table listing
  244.     X * all the (internet) interfaces present on a machine,
  245.     X * along with their subnet masks.  Then when inet_snetof
  246.     X * is called, it can quickly scan this table.
  247.     X *
  248.     X * Unfortunately, there "ain't no graceful way" to handle
  249.     X * certain situations.  For example, the kernel permits
  250.     X * arbitrary subnet bits -- that is, you could have a
  251.     X * 22 bit network field and a 10 bit subnet field.
  252.     X * However, due to braindamage at the user level, in
  253.     X * such sterling routines as getnetbyaddr, you need to
  254.     X * have a subnet mask which is an even multiple of 8.
  255.     X * Unless you are running with class C subnets, in which
  256.     X * case it should be a multiple of 4.  Because of this rot,
  257.     X * if you have non-multiples of 4 bits of subnet, you should
  258.     X * define DAMAGED_NETMASK when you compile.  This will round
  259.     X * things off to a multiple of 8 bits.
  260.     X *
  261.     X * Finally, you may want subnet support even if your system doesn't
  262.     X * support the ioctls to get subnet mask information.  If you want
  263.     X * such a thing, you can define NETMASK to be a constant that is
  264.     X * the subnet mask for your network.
  265.     X *
  266.     X * And don't *even* get me started on how the definitions of the inet_foo()
  267.     X * routines changed between 4.2 and 4.3, making internet addresses
  268.     X * be unsigned long vs. struct in_addr.  Don't blame me if this
  269.     X * won't lint...
  270.     X */
  271.     X
  272.     X/*
  273.     X * One structure for each interface, containing
  274.     X * the network number and subnet mask, stored in HBO.
  275.     X */
  276.     Xstruct in_if {
  277.     X    u_long    i_net;        /* Network number, shifted right */
  278.     X    u_long    i_subnetmask;    /* Subnet mask for this if */
  279.     X    int    i_bitshift;    /* How many bits right for outside */
  280.     X};
  281.     X
  282.     X/*
  283.     X * Table (eventually, once we malloc) of
  284.     X * internet interface subnet information.
  285.     X */
  286.     Xstatic    struct in_if    *in_ifsni;
  287.     X
  288.     Xstatic    int        if_count;
  289.     X
  290.     X/*
  291.     X * Get the network interface configuration,
  292.     X * and squirrel away the network numbers and
  293.     X * subnet masks of each interface.  Return
  294.     X * number of interfaces found, or -1 on error.
  295.     X * N.B.: don't call this more than once...
  296.     X */
  297.     X
  298.     Xgetifconf()
  299.     X{
  300.     X#ifndef NETMASK
  301.     X    register int    i, j;
  302.     X    int        s;
  303.     X    struct ifconf    ifc;
  304.     X    char        buf[1024];
  305.     X    register struct ifreq    *ifr;
  306.     X        int        inet_netof();
  307.     X    u_long        addr;
  308.     X
  309.     X    /*
  310.     X     * Find out how many interfaces we have, and malloc
  311.     X     * room for information about each one.
  312.     X     */
  313.     X
  314.     X    s = socket(AF_INET, SOCK_DGRAM, 0);
  315.     X    if (s < 0)
  316.     X        return (-1);
  317.     X
  318.     X    ifc.ifc_buf = buf;
  319.     X    ifc.ifc_len = sizeof (buf);
  320.     X
  321.     X    if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
  322.     X        (void) close(s);
  323.     X        return (-1);
  324.     X    }
  325.     X
  326.     X    /*
  327.     X     * if_count here is the count of possible
  328.     X     * interfaces we may be interested in... actual
  329.     X     * interfaces may be less (some may not be internet,
  330.     X     * not all are necessarily up, etc.)
  331.     X     */
  332.     X
  333.     X    if_count = ifc.ifc_len / sizeof (struct ifreq);
  334.     X
  335.     X    in_ifsni = (struct in_if *)
  336.     X        malloc((unsigned) if_count * sizeof (struct in_if));
  337.     X    if (in_ifsni == 0) {
  338.     X        (void) close(s);
  339.     X        return (-1);
  340.     X    }
  341.     X
  342.     X    for (i = j = 0; i < if_count; ++i) {
  343.     X        struct sockaddr_in *s_in;
  344.     X
  345.     X        ifr = &ifc.ifc_req[i];
  346.     X        if (ioctl(s, SIOCGIFFLAGS, ifr) < 0)
  347.     X            continue;
  348.     X        if ((ifr->ifr_flags & IFF_UP) == 0)
  349.     X            continue;
  350.     X        if (ioctl(s, SIOCGIFADDR, ifr) < 0)
  351.     X            continue;
  352.     X        if (ifr->ifr_addr.sa_family != AF_INET)
  353.     X            continue;
  354.     X        s_in = (struct sockaddr_in *) &ifr->ifr_addr;
  355.     X        addr = s_in->sin_addr.s_addr;
  356.     X        in_ifsni[j].i_net = inet_netof(s_in->sin_addr);
  357.     X        if (ioctl(s, SIOCGIFNETMASK, ifr) < 0)
  358.     X            continue;
  359.     X        s_in = (struct sockaddr_in *) &ifr->ifr_addr;
  360.     X        in_ifsni[j].i_subnetmask = ntohl(s_in->sin_addr.s_addr);
  361.     X        /*
  362.     X         * The following should "never happen".  But under SunOS
  363.     X         * 3.4, along with the rest of their broken networking code,
  364.     X         * SIOCGIFNETMASK can get a netmask which is 0.  There
  365.     X         * really isn't anything that "right" that we can do
  366.     X         * about it, so we'll set their subnet mask to be their
  367.     X         * *net*work mask.  Which may or may not be right.
  368.     X         */
  369.     X        if (in_ifsni[j].i_subnetmask == 0) {
  370.     X            addr = ntohl(addr);
  371.     X            if (IN_CLASSA(addr))
  372.     X                in_ifsni[j].i_subnetmask = IN_CLASSA_NET;
  373.     X            else if (IN_CLASSB(addr))
  374.     X                in_ifsni[j].i_subnetmask = IN_CLASSB_NET;
  375.     X            else if (IN_CLASSC(addr))
  376.     X                in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
  377.     X            else            /* what to do ... */
  378.     X                in_ifsni[j].i_subnetmask = IN_CLASSC_NET;
  379.     X        } else
  380.     X            in_ifsni[j].i_bitshift = bsr(in_ifsni[j].i_subnetmask);
  381.     X        j++;
  382.     X    }
  383.     X
  384.     X    if_count = j;
  385.     X
  386.     X    (void) close(s);
  387.     X
  388.     X    return (if_count);
  389.     X
  390.     X#else    /* hard-coded subnets */
  391.     X
  392.     X    if_count = 1;
  393.     X
  394.     X    in_ifsni = (struct in_if *) malloc(if_count * sizeof (struct in_if));
  395.     X    if (in_ifsni == 0) {
  396.     X        return (-1);
  397.     X    }
  398.     X    in_ifsni[0].i_net = 0;
  399.     X    in_ifsni[0].i_subnetmask = NETMASK;
  400.     X    in_ifsni[0].i_bitshift = bsr(in_ifsni[0].i_subnetmask);
  401.     X    return (if_count);
  402.     X#endif
  403.     X}
  404.     X
  405.     X
  406.     X/*
  407.     X * Return the (sub)network number from an internet address.
  408.     X * "in" is in NBO, return value in host byte order.
  409.     X * If "in" is not a subnet, return 0.
  410.     X */
  411.     X
  412.     Xu_long
  413.     Xinet_snetof(in)
  414.     X    u_long    in;
  415.     X{
  416.     X    register int    j;
  417.     X    register u_long    i = ntohl(in);
  418.     X    register u_long    net;
  419.     X    int        inet_netof(), inet_lnaof();
  420.     X    struct in_addr in_a;
  421.     X
  422.     X    in_a.s_addr = in;
  423.     X    net = inet_netof(in_a);
  424.     X
  425.     X    /*
  426.     X     * Check whether network is a subnet;
  427.     X     * if so, return subnet number.
  428.     X     */
  429.     X    for (j = 0; j < if_count; ++j)
  430.     X#ifdef NETMASK
  431.     X        if (1) {
  432.     X#else
  433.     X        if (net == in_ifsni[j].i_net) {
  434.     X#endif
  435.     X            net = i & in_ifsni[j].i_subnetmask;
  436.     X            in_a.s_addr = htonl(net);
  437.     X            if (inet_lnaof(in_a) == 0)
  438.     X                return (0);
  439.     X            else
  440.     X                return (net >> in_ifsni[j].i_bitshift);
  441.     X        }
  442.     X
  443.     X    return (0);
  444.     X}
  445.     X
  446.     X
  447.     X/*
  448.     X * Return the number of bits required to
  449.     X * shift right a mask into a getnetent-able entity.
  450.     X */
  451.     X
  452.     Xbsr(mask)
  453.     X    register long    mask;
  454.     X{
  455.     X    register int    count = 0;
  456.     X
  457.     X    if (mask == 0)        /* "never happen", except with SunOS 3.4 */
  458.     X        return (0);
  459.     X
  460.     X    while ((mask & 1) == 0) {
  461.     X        ++count;
  462.     X        mask >>= 1;
  463.     X    }
  464.     X#ifdef DAMAGED_NETMASK
  465.     X    count /= 8;            /* XXX gag retch puke barf */
  466.     X    count *= 8;
  467.     X#endif
  468.     X    return (count);
  469.     X}
  470.     X
  471.     X#endif
  472. SHAR_EOF
  473. if test 6645 -ne "`wc -c < 'subnet.c'`"
  474. then
  475.     echo shar: error transmitting "'subnet.c'" '(should have been 6645 characters)'
  476. fi
  477. echo "Done with directory 'server'"
  478. cd ..
  479. fi
  480. if test -d 'xmit'
  481. then
  482. echo "Entering directory 'xmit'"
  483. cd xmit
  484. echo shar: extracting "'nntpxmit.c'" '(27564 characters)'
  485. sed 's/^    X//' << \SHAR_EOF > 'nntpxmit.c'
  486.     X#ifndef lint
  487.     Xstatic char * rcsid = "@(#)$Header: nntpxmit.c,v 1.7 91/03/19 03:03:16 sob Exp $";
  488.     X#endif
  489.     X/* nntpxmit - transmit netnews articles across the internet with nntp
  490.     X**
  491.     X** This program is for transmitting netnews articles between sites
  492.     X** that offer the NNTP service, internet style. There are two forms
  493.     X** of article transmission that can be used in this environment, since
  494.     X** the communication is interactive (and relatively more immediate,
  495.     X** when compared to batched file transfer protocols, like UUCP). They
  496.     X** are: active send (I have `x', do you want it?) and polling (what
  497.     X** have you gotten lately?).
  498.     X**
  499.     X**         A C T I V E   S E N D
  500.     X**
  501.     X** Sites on the UUCP network generally use active send, without asking
  502.     X** in advance (that is, unless you got an article from your neighbor,
  503.     X** or their site is listed in the Path: header already, you assume
  504.     X** they don't have it and send it along). There is an ihave/sendme
  505.     X** protocol for doing active send over batched links, but I claim that
  506.     X** it won't work well because of the high latency between queueing
  507.     X** and actual transfer that UUCP links typically have. That is, you'll
  508.     X** still end up with a high rate of duplicate articles being sent over
  509.     X** that type of link.
  510.     X**
  511.     X** With NNTP-based IHAVE, the update window in which another site can
  512.     X** give the remote the article you just offered him is the time between
  513.     X** the remote telling you it doesn't have the article, and your
  514.     X** completed transfer of the article (pretty small). In practice, we
  515.     X** still get duplicates, but generally from two problems: synchronized
  516.     X** transmission of an article from two different neighbors (this can
  517.     X** only be fixed by putting inews(1) into nntpd), and by articles
  518.     X** being accepting during an expire(1) run (expire locks out inews
  519.     X** processing while it is running, and articles collect until expire
  520.     X** is done; since accepted article message-ids aren't added to
  521.     X** the history file until expire is done, several clients can offer
  522.     X** you the same article, and you'll accept all the copies offered you.
  523.     X** When rnews gets run after expire, it will reject the duplicates).
  524.     X**
  525.     X**         P O L L I N G
  526.     X**
  527.     X** Polling presents some article and distribution security problems,
  528.     X** because the server has no contol over what a transmission client
  529.     X** will ask for, and it must therefore control what it tells a client
  530.     X** in response to a query.
  531.     X**
  532.     X** Articles that appear in local newsgroup hierarchies, or appear in
  533.     X** the generally distributed USENET newsgroups with local distributions
  534.     X** have to be filtered out from the list of message-IDs that the server
  535.     X** gives to a client in response to a NEWNEWS query, or filtered when
  536.     X** the server fetches the articles off the disk in response to an
  537.     X** ARTICLE command (and therefore has complete access to the required
  538.     X** information). Otherwise, distributions will leak.
  539.     X**
  540.     X** The other problem with polling is that a good client should keep track
  541.     X** of when it last successfully polled a server, so that it doesn't force
  542.     X** the server to dump its entire history file across the network, and this
  543.     X** involves more file locking and manipulations routines.
  544.     X**
  545.     X** nntpxmit only implements active send, for now.
  546.     X**
  547.     X** Erik E. Fair <fair@ucbarpa.berkeley.edu>, Dec 4, 1987
  548.     X** Stan Barber <sob@bcm.tmc.edu>, Jan 1, 1989
  549.     X*/
  550.     X
  551.     X#include "../common/conf.h"
  552.     X#include "nntpxmit.h"
  553.     X#include <stdio.h>
  554.     X#include <errno.h>
  555.     X#include <ctype.h>
  556.     X#include <sys/types.h>
  557.     X#ifdef LAI_TCP
  558.     X#include <sys/bsdtypes.h>
  559.     X#endif
  560.     X#include <sys/time.h>
  561.     X#if defined(BSD_42) || defined(BSD_43)
  562.     X#include <sys/resource.h>
  563.     X#else
  564.     X#include <sys/times.h>
  565.     Xextern    time_t    time();
  566.     X#endif
  567.     X#include <sys/file.h>
  568.     X#include <fcntl.h>
  569.     X#include <signal.h>
  570.     X#ifdef USG
  571.     X#include "sysexits.h"
  572.     X#else
  573.     X#include <sysexits.h>
  574.     X#endif
  575.     X#ifdef    SYSLOG
  576.     X#ifdef FAKESYSLOG
  577.     X#include "../server/fakesyslog.h"
  578.     X#else
  579.     X#include <syslog.h>
  580.     X#endif
  581.     X#endif    /* SYSLOG */
  582.     X#include "../common/nntp.h"
  583.     X#include "llist.h"
  584.     X
  585.     X#define    MAXFNAME    BUFSIZ    /* maximum filename size - big enough? */
  586.     X#define    FCLOSE(fp)    if (fp) (void) fclose(fp); (fp) = (FILE *)NULL
  587.     X
  588.     Xchar    *getline();
  589.     Xchar    *getmsgid();
  590.     Xchar    *errmsg();
  591.     Xvoid    requeue();
  592.     XSIGRET    catchsig();
  593.     Xvoid    restsig();
  594.     Xvoid    logstats();
  595.     Xvoid    log();
  596.     Xint    interrupted();
  597.     X
  598.     X/*
  599.     X** Globals that certain things need.
  600.     X**
  601.     X** Various subroutines want the program name to report errors.
  602.     X** The queue file, queue file pointer and current article name are
  603.     X** there to write out the state of the queue file from a signal handler
  604.     X** (that is, the list of unsent and (possibly) failed articles) so
  605.     X** that when next we try sending to a given remote site, we don't send
  606.     X** stuff we've already sent.
  607.     X*/
  608.     Xchar    *Pname;            /* this program's invocation name */
  609.     Xchar    *Host;            /* current remote host */
  610.     Xchar    *Qfile;            /* current queue file we're operating on */
  611.     XFILE    *Qfp;            /* the (FILE *) for above */
  612.     Xchar    Article[MAXFNAME];    /* current article filename */
  613.     X
  614.     X/*
  615.     X** Some flags, toggled by arguments
  616.     X*/
  617.     X#define    TOGGLE(boolean)    (boolean) = !(boolean)
  618.     Xchar    Debug = FALSE;
  619.     Xchar    Report_Stats = TRUE;
  620.     Xchar    ReQueue_Fails = TRUE;
  621.     X
  622.     Xchar    *USAGE = "USAGE: nntpxmit [-d][-s][-r][-T][-F][-D] hostname|hostname:file [...]";
  623.     Xchar    *Fmt = "%s localhost %s[%d]: %s\n";
  624.     Xchar    *E_fopen = "fopen(%s, \"%s\"): %s";
  625.     Xchar    *E_unlk = "unlink(%s): %s";
  626.     X
  627.     Xll_t    FailedArticles;        /* list of failed articles */
  628.     X
  629.     Xstruct {
  630.     X    u_long    offered;
  631.     X    u_long    accepted;
  632.     X    u_long    rejected;
  633.     X    u_long    failed;
  634.     X} Stats = {0L, 0L, 0L, 0L};
  635.     X
  636.     Xdouble Tbegin, Tend;        /* transfer timestamps */
  637.     X
  638.     Xextern    int    errno;
  639.     Xextern     int    strncmp();
  640.     Xextern    char    *rindex();
  641.     Xextern    char    *index();
  642.     Xextern    char    *mktemp();
  643.     Xextern    char    *strcpy();
  644.     Xextern    char    *strcat();
  645.     X
  646.     X#ifdef    USG
  647.     Xvoid
  648.     Xbzero(s, l)
  649.     Xregister caddr_t s;
  650.     Xregister int    l;
  651.     X{
  652.     X    while(l-- > 0) *s++ = 0;
  653.     X}
  654.     X#endif    /* USG */
  655.     X
  656.     Xmain(ac, av)
  657.     Xint    ac;
  658.     Xchar    *av[];
  659.     X{
  660.     X    register int    i;
  661.     X    int    transport = T_IP_TCP;    /* default is IP/TCP */
  662.     X    int    isQfile = TRUE;        /* file arg is a Queue file */
  663.     X#if    defined(BSD_42) || defined(BSD_43)
  664.     X    struct timeval tod;
  665.     X    struct timezone tz;
  666.     X
  667.     X    (void) gettimeofday(&tod, &tz);
  668.     X    Tbegin = tod.tv_sec + (double)tod.tv_usec/1000000.;
  669.     X#else
  670.     X    Tbegin = (double) time((time_t *)NULL);
  671.     X#endif
  672.     X
  673.     X    Pname = ((Pname = rindex(av[0],'/')) ? Pname + 1 : av[0]);
  674.     X    
  675.     X    if (ac < 2) {
  676.     X        fprintf(stderr, "%s: %s\n", Pname, USAGE);
  677.     X        exit(EX_USAGE);
  678.     X    }
  679.     X
  680.     X#ifdef    SYSLOG
  681.     X    /* 4.2 BSD openlog has only two args */
  682.     X#ifdef    BSD_42
  683.     X    (void) openlog(Pname, LOG_PID);
  684.     X#else
  685.     X    (void) openlog(Pname, LOG_PID, SYSLOG);
  686.     X#endif    /* BSD_42 */
  687.     X#endif    /* SYSLOG */
  688.     X
  689.     X    for(i = 1; i < ac; i++) {
  690.     X        if (av[i][0] == '-') {
  691.     X            switch(av[i][1]) {
  692.     X            case 'T':
  693.     X                transport = T_IP_TCP;
  694.     X                break;
  695.     X            case 'D':
  696.     X                transport = T_DECNET;
  697.     X                break;
  698.     X            case 'F':
  699.     X                transport = T_FD;
  700.     X                break;
  701.     X            case 's':
  702.     X                TOGGLE(Report_Stats);
  703.     X                break;
  704.     X            case 'd':
  705.     X                TOGGLE(Debug);
  706.     X                break;
  707.     X            case 'r':
  708.     X                TOGGLE(ReQueue_Fails);
  709.     X                break;
  710.     X            case 'a':
  711.     X                isQfile = FALSE;
  712.     X                break;
  713.     X            default:
  714.     X                fprintf(stderr, "%s: no such option: -%c\n",
  715.     X                    Pname, av[i][1]);
  716.     X                fprintf(stderr, "%s: %s\n", Pname, USAGE);
  717.     X                exit(EX_USAGE);
  718.     X            }
  719.     X            continue;
  720.     X        }
  721.     X
  722.     X        /*
  723.     X        ** OK, it wasn't an option, therefore it must be a
  724.     X        ** hostname, filename pair.
  725.     X        **
  726.     X        ** If the user typed host::file, then it's DECNET,
  727.     X        ** whether they remembered the "-D" option or not.
  728.     X        */
  729.     X        Host = av[i];
  730.     X        if ((Qfile = index(Host, ':')) != (char *)NULL) {
  731.     X            if (Qfile[1] == ':') {
  732.     X                transport = T_DECNET;
  733.     X                *Qfile++ = '\0';
  734.     X            } else if (transport != T_FD)
  735.     X                transport = T_IP_TCP;
  736.     X            *Qfile++ = '\0';
  737.     X        } else
  738.     X            Qfile = Host;
  739.     X
  740.     X        bzero((caddr_t)&Stats, sizeof(Stats));
  741.     X        if (isQfile) {
  742.     X            if (sendnews(Host, transport, Qfile, isQfile) && Report_Stats) {
  743.     X                logstats();
  744.     X            }
  745.     X        } else {
  746.     X            /* one-shot */
  747.     X            (void) strcpy(Article, Qfile);
  748.     X            exit(sendnews(Host, transport, Qfile, isQfile) ? EX_OK : EX_TEMPFAIL);
  749.     X        }
  750.     X    }
  751.     X    exit(EX_OK);
  752.     X}
  753.     X
  754.     X/*
  755.     X** Calculate how much time we've used,
  756.     X** and report that (and the transfer statistics).
  757.     X**
  758.     X*/
  759.     Xvoid
  760.     Xlogstats()
  761.     X{
  762.     X    static double ouser = 0.0, osys = 0.0;
  763.     X    double user, sys;
  764.     X    char buf[BUFSIZ];
  765.     X#if    defined(BSD_42) || defined(BSD_43)
  766.     X    struct rusage self, kids;
  767.     X    struct timeval tod;
  768.     X    struct timezone tzdummy;
  769.     X
  770.     X    (void) getrusage(RUSAGE_SELF, &self);
  771.     X    (void) getrusage(RUSAGE_CHILDREN, &kids);
  772.     X    (void) gettimeofday(&tod, &tzdummy);
  773.     X
  774.     X    Tend = tod.tv_sec + (double)tod.tv_usec/1000000.;
  775.     X
  776.     X    user = self.ru_utime.tv_sec + kids.ru_utime.tv_sec +
  777.     X        (double) self.ru_utime.tv_usec/1000000. +
  778.     X        (double) kids.ru_utime.tv_usec/1000000.;
  779.     X    
  780.     X    sys = self.ru_stime.tv_sec + kids.ru_stime.tv_sec +
  781.     X        (double) self.ru_stime.tv_usec/1000000. +
  782.     X        (double) kids.ru_stime.tv_usec/1000000.;
  783.     X#else
  784.     X#define    HZ    60.0    /* typical system clock ticks - param.h */
  785.     X    struct tms    cpu;
  786.     X
  787.     X    (void) times(&cpu);
  788.     X
  789.     X    Tend = (double) time((time_t *)NULL);
  790.     X    user = (double)(cpu.tms_utime + cpu.tms_cutime) / HZ;
  791.     X    sys  = (double)(cpu.tms_stime + cpu.tms_cstime) / HZ;
  792.     X#endif
  793.     X    sprintf(buf,
  794.     X        "%s stats %lu offered %lu accepted %lu rejected %lu failed",
  795.     X        Host, Stats.offered, Stats.accepted, Stats.rejected,
  796.     X        Stats.failed);
  797.     X    log(L_INFO, buf);
  798.     X    sprintf(buf, "%s xmit user %.3f system %.3f elapsed %.3f",
  799.     X        Host, (user - ouser), (sys - osys), (Tend - Tbegin));
  800.     X    log(L_INFO, buf);
  801.     X    /* reset reference point */
  802.     X    Tbegin = Tend;    
  803.     X    ouser = user;
  804.     X    osys = sys;
  805.     X}
  806.     X
  807.     X/*
  808.     X** Given a hostname to connect to, and a file of filenames (which contain
  809.     X** netnews articles), send those articles to the named host using NNTP.
  810.     X**
  811.     X** Return code behavior is different depending upon isQfile.
  812.     X**
  813.     X**    TRUE    - return TRUE if we contacted the remote and started
  814.     X**          transferring news - this is to decide whether to
  815.     X**          record CPU and transfer statistics.
  816.     X**
  817.     X**    FALSE    - a one-shot file transfer - return TRUE or FALSE depending
  818.     X**          upon whether we successfully transferred the one article.
  819.     X*/
  820.     Xsendnews(host, transport, file, isQfile)
  821.     Xchar    *host, *file;
  822.     Xint    transport, isQfile;
  823.     X{
  824.     X#ifdef    FTRUNCATE
  825.     X    char    *mode = "r+";        /* so we can use ftruncate() */
  826.     X#else
  827.     X    char    *mode = "r";
  828.     X#endif    /* FTRUNCATE */
  829.     X    char    *msgid;
  830.     X
  831.     X    if ((Qfp = fopen(file, mode)) == (FILE *)NULL) {
  832.     X        char    buf[BUFSIZ];
  833.     X
  834.     X        sprintf(buf, E_fopen, file, mode, errmsg(errno));
  835.     X        log(L_WARNING, buf);
  836.     X        return(FALSE);
  837.     X    }
  838.     X
  839.     X    /*
  840.     X    ** interlock with other copies of this process.
  841.     X    ** non-blocking.
  842.     X    */
  843.     X    if (isQfile) {
  844.     X        if (!lockfd(fileno(Qfp), file, DONT_BLOCK)) {
  845.     X            FCLOSE(Qfp);
  846.     X            return(FALSE);
  847.     X        }
  848.     X    }
  849.     X
  850.     X    /*
  851.     X    ** Open a connection to the remote server
  852.     X    */
  853.     X    if (hello(host, transport) == FAIL) {
  854.     X        FCLOSE(Qfp);
  855.     X        return(FALSE);
  856.     X    }
  857.     X
  858.     X    if (isQfile) {
  859.     X        /*
  860.     X        ** We're sending a batch queue:
  861.     X        **    open article
  862.     X        **    get message-ID
  863.     X        **    send "IHAVE <message-ID>" to remote
  864.     X        **    read their reply
  865.     X        **    send article if appropriate
  866.     X        **    iterate to end of queue file
  867.     X        */
  868.     X        catchsig(interrupted);
  869.     X
  870.     X        while ((msgid = getline(Qfp, Article, sizeof(Article))) != NULL) {
  871.     X            if (!sendarticle(host, Article, msgid)) {
  872.     X                requeue(Article, msgid);
  873.     X                Article[0] = '\0';
  874.     X                cleanup();
  875.     X                goodbye(DONT_WAIT);
  876.     X                restsig();
  877.     X                return(TRUE);
  878.     X            }
  879.     X        }
  880.     X
  881.     X        cleanup();
  882.     X        goodbye(WAIT);
  883.     X        restsig();
  884.     X        return(TRUE);
  885.     X    } else {
  886.     X        /*
  887.     X        ** Qfp is a netnews article - this is a one-shot
  888.     X        ** operation, exit code dependent upon remote's
  889.     X        ** acceptance of the article
  890.     X        */
  891.     X        register int    retcode;
  892.     X
  893.     X        FCLOSE(Qfp);
  894.     X        retcode = sendarticle(host, file, (char *) NULL);
  895.     X        goodbye(retcode ? WAIT : DONT_WAIT);
  896.     X        return(retcode && Stats.accepted == 1 && Stats.failed == 0);
  897.     X    }
  898.     X}
  899.     X
  900.     X/*
  901.     X** Perform one transfer operation:
  902.     X**    Give IHAVE command
  903.     X**    Wait for reply, and send article if they ask for it
  904.     X**    Wait for transfer confirmation, and requeue the article
  905.     X**        if they drop it.
  906.     X**    Watch all network I/O for errors, return FALSE if
  907.     X**        the connection fails and we have to cleanup.
  908.     X*/
  909.     Xsendarticle(host, file, msgid)
  910.     Xchar    *host;
  911.     Xchar    *file;
  912.     Xchar    *msgid;
  913.     X{
  914.     X    register int    code;
  915.     X    FILE    *fp = NULL;
  916.     X    int    error;
  917.     X    char    buf[BUFSIZ];
  918.     X    char    *e_xfer = "%s xfer: %s";
  919.     X
  920.     X    errno = 0;
  921.     X    if (msgid == NULL || *msgid == '\0') {
  922.     X        if ((msgid = getmsgid(file, &fp)) == NULL) {
  923.     X            if (fp) { (void) fclose(fp); fp = NULL; }
  924.     X            return TRUE;
  925.     X        }
  926.     X    }
  927.     X    switch(code = ihave(msgid)) {
  928.     X    case CONT_XFER:
  929.     X        /*
  930.     X        ** They want it. Give it to 'em.
  931.     X        */
  932.     X        if (!fp) { fp = fopen(file, "r"); }
  933.     X        if (fp == NULL && errno != ENOENT) {
  934.     X            /* Worse than "No such file or directory"? */
  935.     X            sprintf(buf, E_fopen, file, "r", errmsg(errno));
  936.     X            log(L_WARNING, buf);
  937.     X            goodbye(DONT_WAIT);
  938.     X            exit(EX_OSERR);
  939.     X        }
  940.     X        if (fp == NULL) {
  941.     X            /* Hmph. The file didn't exist. */
  942.     X            error = sendcmd(".");
  943.     X        } else {
  944.     X            error = !sendfile(fp);
  945.     X            (void) fclose(fp);
  946.     X            fp = NULL;
  947.     X        }
  948.     X        if (error) {
  949.     X            sprintf(buf, "%s xfer: sendfile: %s",
  950.     X                host, errmsg(errno));
  951.     X            log(L_NOTICE, buf);
  952.     X            Stats.failed++;
  953.     X            if (fp) { (void) fclose(fp); fp = NULL; }
  954.     X            return(FALSE);
  955.     X        }
  956.     X        /*
  957.     X        ** Did the article transfer OK?
  958.     X        ** Stay tuned to this same socket to find out!
  959.     X        */
  960.     X        errno = 0;
  961.     X        if ((code = readreply(buf, sizeof(buf))) != OK_XFERED) {
  962.     X            Stats.failed++;
  963.     X            if (code < 0) {
  964.     X                if (errno > 0) {
  965.     X                    sprintf(buf, e_xfer, host, errmsg(errno));
  966.     X                    log(L_NOTICE, buf);
  967.     X                } else {
  968.     X                    char errbuf[BUFSIZ];
  969.     X
  970.     X                    sprintf(errbuf, e_xfer, host, buf);
  971.     X                    log(L_NOTICE, errbuf);
  972.     X                if (fp) { (void) fclose(fp); fp = NULL; }
  973.     X                }
  974.     X                return(FALSE);
  975.     X            }
  976.     X            if (ReQueue_Fails && code != ERR_XFERRJCT && fp != NULL) {
  977.     X                requeue(Article, msgid);
  978.     X                Article[0] = '\0';
  979.     X            }
  980.     X        }
  981.     X        break;
  982.     X    case ERR_GOTIT:
  983.     X        /* they don't want it */
  984.     X        break;
  985.     X    case ERR_XFERFAIL:
  986.     X        if (fp) { (void) fclose(fp); fp = NULL; }
  987.     X        /* they can't do it right now, but maybe later */
  988.     X        return(FALSE);
  989.     X        break;
  990.     X    default:
  991.     X        if (code < 0) {
  992.     X            if (errno > 0) {
  993.     X                sprintf(buf, e_xfer, host, errmsg(errno));
  994.     X                log(L_NOTICE, buf);
  995.     X            } else {
  996.     X                sprintf(buf, e_xfer, host, "ihave");
  997.     X                log(L_NOTICE, buf);
  998.     X            }
  999.     X        } else {
  1000.     X            sprintf(buf, "%s improper response to IHAVE: %d while offering %s", host, code, Article);
  1001.     X            log(L_WARNING, buf);
  1002.     X            if (fp) { (void) fclose(fp); fp = NULL; }
  1003.     X        }
  1004.     X        return(FALSE);
  1005.     X    }
  1006.     X    if (fp) { (void) fclose(fp); fp = NULL; }
  1007.     X    return(TRUE);
  1008.     X}
  1009.     X
  1010.     Xchar *
  1011.     Xerrmsg(code)
  1012.     Xint code;
  1013.     X{
  1014.     X    extern int sys_nerr;
  1015.     X    extern char *sys_errlist[];
  1016.     X    static char ebuf[6+5+1];
  1017.     X
  1018.     X    if (code > sys_nerr || code < 0) {
  1019.     X        (void) sprintf(ebuf, "Error %d", code);
  1020.     X        return ebuf;
  1021.     X    } else
  1022.     X        return sys_errlist[code];
  1023.     X}
  1024.     X
  1025.     X/*
  1026.     X** strip leading and trailing spaces
  1027.     X*/
  1028.     Xchar *
  1029.     Xsp_strip(s)
  1030.     Xregister char    *s;
  1031.     X{
  1032.     X    register char    *cp;
  1033.     X
  1034.     X    if (s == NULL)
  1035.     X        return(NULL);
  1036.     X
  1037.     X    if (*s == '\0')
  1038.     X        return(s);
  1039.     X    
  1040.     X    cp = &s[strlen(s) - 1];
  1041.     X    while(cp > s && isspace(*cp))
  1042.     X        cp--;
  1043.     X
  1044.     X    *++cp = '\0';    /* zap trailing spaces */
  1045.     X
  1046.     X    for(cp = s; *cp && isspace(*cp); cp++)
  1047.     X        continue;
  1048.     X
  1049.     X    return(cp);    /* return pointer to first non-space */
  1050.     X}
  1051.     X
  1052.     X/*
  1053.     X** convert `s' to lower case
  1054.     X*/
  1055.     Xchar *
  1056.     Xlcase(s)
  1057.     Xregister char    *s;
  1058.     X{
  1059.     X    register char    *cp;
  1060.     X
  1061.     X    if (s == (char *)NULL)
  1062.     X        return(s);
  1063.     X
  1064.     X    for(cp = s; *cp != '\0'; cp++)
  1065.     X        if (isupper(*cp))
  1066.     X            *cp = tolower(*cp);
  1067.     X    return(s);
  1068.     X}
  1069.     X
  1070.     X/*
  1071.     X** Get the message-id header field data with a minimum of fuss.
  1072.     X*/
  1073.     Xchar *
  1074.     Xgetmsgid(file, fpp)
  1075.     Xchar *file;
  1076.     XFILE **fpp;
  1077.     X{
  1078.     X    static    char    buf[BUFSIZ];
  1079.     X    static    char    msgid[] = "message-id";
  1080.     X    register char    *cp, *cp2;
  1081.     X
  1082.     X    *fpp = fopen(file, "r");
  1083.     X    if (*fpp == NULL) return NULL;
  1084.     X
  1085.     X    while(fgets(buf, sizeof(buf), *fpp) != NULL) {
  1086.     X        switch(buf[0]) {
  1087.     X        case '\n':
  1088.     X            (void) fclose(*fpp);
  1089.     X            *fpp = NULL;
  1090.     X            return NULL;    /* EOH, we failed */
  1091.     X        case 'M':
  1092.     X        case 'm':
  1093.     X            cp = index(buf, ':');
  1094.     X            if (cp == NULL) continue;
  1095.     X            *cp++ = '\0';
  1096.     X            if (strncmp(lcase(buf), msgid, strlen(msgid)) == 0) {
  1097.     X                /* dump extraneous trash - umass.bitnet */
  1098.     X                /* hope nobody quotes an '>' in a msgid */
  1099.     X                cp2 = index(cp, '>');
  1100.     X                if (cp2 != NULL) *++cp2 = '\0';
  1101.     X                (void) rewind(*fpp);
  1102.     X                return(sp_strip(cp));
  1103.     X            }
  1104.     X            break;
  1105.     X        }
  1106.     X    }
  1107.     X    (void) fclose(*fpp);
  1108.     X    *fpp = NULL;
  1109.     X    return NULL;    /* EOF, failed. */
  1110.     X}
  1111.     X
  1112.     X#ifdef    notdef    /* nobody obeys the triply damned protocol anyway! */
  1113.     X/*
  1114.     X** Special characters, see RFC822, appendix D.
  1115.     X*/
  1116.     Xisspecial(c)
  1117.     Xchar    c;
  1118.     X{
  1119.     X    char    *specials = "()<>@,;:\\\".[]";
  1120.     X
  1121.     X    return(index(specials, c) != (char *)NULL ? TRUE : FALSE);
  1122.     X}
  1123.     X
  1124.     X/*
  1125.     X** Check on the validity of an RFC822 message-id
  1126.     X**
  1127.     X** By The Book, RFC822 Appendix D.
  1128.     X**    msg-id        = "<" addr-spec ">"
  1129.     X**    addr-spec    = local-part "@" domain
  1130.     X**    local-part    = word *("." word)
  1131.     X**    word        = atom / quoted-string
  1132.     X**    domain         = sub-domain *("." sub-domain)
  1133.     X**    sub-domain    = domain-ref / domain-literal
  1134.     X**    domain-ref    = atom
  1135.     X**    domain-literal    = "[" *(dtext / quoted-pair) "]"
  1136.     X**
  1137.     X** NOTE: close reading of the RFC822 spec indicates that a fully
  1138.     X**    qualified domain name (i.e. one with at least one dot) is
  1139.     X**    NOT required in the domain part of the addr-spec. However,
  1140.     X**    I've decided to be an asshole and require them, since we'll 
  1141.     X**    all die a slow death later on if I don't at this juncture.
  1142.     X**    To disable, if you disagree with me, see the last return
  1143.     X**    statement. - Erik E. Fair <fair@ucbarpa.berkeley.edu>
  1144.     X**    May 30, 1986
  1145.     X*/
  1146.     Xmsgid_ok(id)
  1147.     Xregister char    *id;
  1148.     X{
  1149.     X    register Langle = FALSE;
  1150.     X    register Rangle = FALSE;
  1151.     X    register local_part = FALSE;
  1152.     X    register at = FALSE;
  1153.     X    register dot = FALSE;
  1154.     X
  1155.     X    /* skip up to the opening angle bracket */
  1156.     X    if (id == (char *)NULL || (id = index(id, '<')) == (char *)NULL)
  1157.     X        return(FALSE);        /* don't waste my time! */
  1158.     X
  1159.     X    for(; *id != '\0'; id++) {
  1160.     X        switch(*id) {
  1161.     X        case '<':
  1162.     X            if (Langle) return(FALSE);
  1163.     X            Langle = local_part = TRUE;
  1164.     X            break;
  1165.     X        case '>':
  1166.     X            if (Rangle || !Langle || !at) return(FALSE);
  1167.     X            else Rangle = TRUE;
  1168.     X            break;
  1169.     X        case '@':        /* should be a domain spec */
  1170.     X            at = TRUE;
  1171.     X            local_part = FALSE;
  1172.     X            break;
  1173.     X        case '.':
  1174.     X            dot = at;
  1175.     X            break;
  1176.     X        case '\\':
  1177.     X            /*
  1178.     X            ** quoted pair; this disallows NULs, but how
  1179.     X            ** many mailers would die if someone used one?
  1180.     X            */
  1181.     X            if (!local_part || (*++id) == '\0') return(FALSE);
  1182.     X            break;
  1183.     X        case '"':
  1184.     X            /*
  1185.     X            ** quoted string
  1186.     X            */
  1187.     X            if (!local_part) return(FALSE);
  1188.     X            do {
  1189.     X                switch(*++id) {
  1190.     X                case '\\':
  1191.     X                    if ((*++id) == '\0') return(FALSE);
  1192.     X                    break;
  1193.     X                case '\r':
  1194.     X                    return(FALSE);
  1195.     X                }
  1196.     X            } while(*id != '\0' && *id != '"');
  1197.     X            break;
  1198.     X        case '[':
  1199.     X            /*
  1200.     X            ** domain literal
  1201.     X            */
  1202.     X            if (local_part) return(FALSE);
  1203.     X            do {
  1204.     X                switch(*++id) {
  1205.     X                case '\\':
  1206.     X                    if ((*++id) == '\0') return(FALSE);
  1207.     X                    break;
  1208.     X                case '\r':
  1209.     X                    return(FALSE);
  1210.     X                }
  1211.     X            } while(*id != '\0' && *id != ']');
  1212.     X            break;
  1213.     X        default:
  1214.     X            if (!isascii(*id) || iscntrl(*id) || isspace(*id) || isspecial(*id))
  1215.     X                return(FALSE);    /* quit immediately */
  1216.     X            break;
  1217.     X        }
  1218.     X    }
  1219.     X    return(at && dot && Langle && Rangle);
  1220.     X}
  1221.     X#else notdef
  1222.     X
  1223.     X/*
  1224.     X** Simpleton's check for message ID syntax.
  1225.     X** A concession to the realities of the ARPA Internet.
  1226.     X*/
  1227.     Xmsgid_ok(s)
  1228.     Xregister char *s;
  1229.     X{
  1230.     X    register char    c;
  1231.     X    register in_msgid = FALSE;
  1232.     X
  1233.     X    if (s == (char *)NULL)
  1234.     X        return(FALSE);
  1235.     X
  1236.     X    while((c = *s++) != '\0') {
  1237.     X        if (!isascii(c) || iscntrl(c) || isspace(c))
  1238.     X            return(FALSE);
  1239.     X        switch(c) {
  1240.     X        case '<':
  1241.     X            in_msgid = TRUE;
  1242.     X            break;
  1243.     X        case '>':
  1244.     X            return(in_msgid);
  1245.     X        }
  1246.     X    }
  1247.     X    return(FALSE);
  1248.     X}
  1249.     X#endif    /* notdef */
  1250.     X
  1251.     X/*
  1252.     X** Read the header of a netnews article, snatch the message-id therefrom,
  1253.     X** and ask the remote if they have that one already.
  1254.     X*/
  1255.     Xihave(id)
  1256.     Xchar    *id;
  1257.     X{
  1258.     X    register int    code;
  1259.     X    char    buf[BUFSIZ];
  1260.     X
  1261.     X    if (id == NULL || *id == '\0') {
  1262.     X        /*
  1263.     X        ** something botched locally with the article
  1264.     X        ** so we don't send it, but we don't break off
  1265.     X        ** communications with the remote either.
  1266.     X        */
  1267.     X        sprintf(buf, "%s: message-id missing!", Article);
  1268.     X        log(L_DEBUG, buf);
  1269.     X        return(ERR_GOTIT);
  1270.     X    }
  1271.     X
  1272.     X    if (!msgid_ok(id)) {
  1273.     X        sprintf(buf, "%s: message-id syntax error: %s", Article, id);
  1274.     X        log(L_DEBUG, buf);
  1275.     X        return(ERR_GOTIT);
  1276.     X    }
  1277.     X
  1278.     Xagain:
  1279.     X    sprintf(buf, "IHAVE %s", id);
  1280.     X    Stats.offered++;
  1281.     X
  1282.     X    switch(code = converse(buf, sizeof(buf))) {
  1283.     X    case CONT_XFER:
  1284.     X        Stats.accepted++;
  1285.     X        return(code);
  1286.     X    case ERR_GOTIT:
  1287.     X        Stats.rejected++;
  1288.     X        return(code);
  1289.     X#ifdef AUTH
  1290.     X    case ERR_NOAUTH:
  1291.     X        xmitauth(Host);
  1292.     X        goto again;
  1293.     X#endif
  1294.     X    default:
  1295.     X        return(code);
  1296.     X    }
  1297.     X}
  1298.     X
  1299.     X/*
  1300.     X** Read the next line from fp into line,
  1301.     X** break it apart into filename and message-id,
  1302.     X** and return a pointer to the message-id.
  1303.     X** Returns "" if no message-id.
  1304.     X** Returns NULL at end of file.
  1305.     X*/
  1306.     Xchar *
  1307.     Xgetline(fp, line, len)
  1308.     XFILE    *fp;
  1309.     Xchar    *line;
  1310.     Xint    len;
  1311.     X{
  1312.     X    register char    *cp;
  1313.     X
  1314.     X    do {
  1315.     X        if (fgets(line, len, fp) == NULL) return NULL;
  1316.     X        line[len - 1] = '\0';
  1317.     X
  1318.     X        cp = index(line, '\n');
  1319.     X        if (cp != NULL) *cp = '\0';
  1320.     X    } while (line[0] == '\0');
  1321.     X
  1322.     X    cp = &line[0];
  1323.     X    while (*cp != '\0' && !isspace(*cp)) ++cp;
  1324.     X    if (*cp != '\0') {
  1325.     X        *cp++ = '\0';
  1326.     X        while (*cp != '\0' && isspace(*cp)) ++cp;
  1327.     X        /* cp now points to the message-id, if any. */
  1328.     X    }
  1329.     X    return cp;
  1330.     X}
  1331.     X
  1332.     X/*
  1333.     X** OK, clean up any mess and requeue failed articles
  1334.     X*/
  1335.     Xcleanup()
  1336.     X{
  1337.     X    dprintf(stderr, "%s: cleanup()\n", Pname);
  1338.     X    if (Qfp == (FILE *)NULL || Qfile == (char *)NULL)
  1339.     X        return;
  1340.     X
  1341.     X    if ((ReQueue_Fails && Stats.failed > 0) || !feof(Qfp)) {
  1342.     X        rewrite();
  1343.     X    } else {
  1344.     X        /*
  1345.     X        ** Nothing to clean up after, reset stuff and
  1346.     X        ** nuke the queue file.
  1347.     X        */
  1348.     X        requeue((char *)NULL, (char *)NULL);
  1349.     X        if (feof(Qfp)) {
  1350.     X            dprintf(stderr, "%s: unlink(%s)\n", Pname, Qfile);
  1351.     X            if (unlink(Qfile) < 0) {
  1352.     X                char    buf[BUFSIZ];
  1353.     X
  1354.     X                sprintf(buf, E_unlk, Qfile, errmsg(errno));
  1355.     X                log(L_WARNING, buf);
  1356.     X            }
  1357.     X        }
  1358.     X        FCLOSE(Qfp);
  1359.     X    }
  1360.     X}
  1361.     X 
  1362.     X/*
  1363.     X** Add an article file name to an allocated linked list,
  1364.     X** so that we can rewrite it back to the queue file later.
  1365.     X** Calling this with a NULL pointer resets the internal pointer.
  1366.     X*/
  1367.     Xvoid
  1368.     Xrequeue(article, msgid)
  1369.     Xchar *msgid;
  1370.     Xchar *article;
  1371.     X{
  1372.     X    char buf[BUFSIZ];
  1373.     X    static ll_t *lp = &FailedArticles;
  1374.     X
  1375.     X    if (article == (char *)NULL) {
  1376.     X        dprintf(stderr, "%s: requeue(): reset\n", Pname);
  1377.     X        goto reset;        /* this is for our static pointer */
  1378.     X    }
  1379.     X
  1380.     X    if (*article == '\0')
  1381.     X        return;
  1382.     X
  1383.     X    (void) strcpy(buf, article);
  1384.     X    if (msgid != NULL && *msgid != '\0') {
  1385.     X        (void) strcat(strcat(buf, " "), msgid);
  1386.     X    }
  1387.     X
  1388.     X    dprintf(stderr, "%s: requeue(%s)\n", Pname, buf);
  1389.     X    if ((lp = l_alloc(lp, buf, strlen(buf) + 1)) == (ll_t *)NULL) {
  1390.     X        fprintf(stderr, "%s: requeue(%s) failed, dumping fail list\n",
  1391.     X            Pname, buf);
  1392.     X        /*
  1393.     X        ** Wow! Did you know that this could blow the stack
  1394.     X        ** if we recurse too deeply? I sure didn't!
  1395.     X        */
  1396.     Xreset:
  1397.     X        l_free(&FailedArticles);
  1398.     X        lp = &FailedArticles;
  1399.     X    }
  1400.     X}
  1401.     X
  1402.     X/*
  1403.     X** Note that if I'm not running as "news" or "usenet" (or whatever
  1404.     X** account is supposed to own netnews), the resultant file will be the
  1405.     X** wrong ownership, permissions, etc.
  1406.     X*/
  1407.     Xrewrite()
  1408.     X{
  1409.     X    register ll_t    *lp;
  1410.     X    register FILE    *tmpfp;
  1411.     X    register int    nart = 0;
  1412.     X    char    *mode = "w+";
  1413.     X    static char template[] = "/tmp/nntpxmitXXXXXX";
  1414.     X    char    buf[BUFSIZ];
  1415.     X    static char    *tempfile = (char *)NULL;
  1416.     X
  1417.     X    dprintf(stderr, "%s: rewrite(%s)\n", Pname, Qfile);
  1418.     X
  1419.     X    if (tempfile == (char *)NULL)    /* should only need this once */
  1420.     X        tempfile = mktemp(template);
  1421.     X
  1422.     X    if ((tmpfp = fopen(tempfile, mode)) == (FILE *)NULL) {
  1423.     X        sprintf(buf, E_fopen, tempfile, mode, errmsg(errno));
  1424.     X        log(L_WARNING, buf);
  1425.     X        FCLOSE(Qfp);
  1426.     X        return;
  1427.     X    }
  1428.     X
  1429.     X    /*
  1430.     X    ** Requeue the rest of the queue file first,
  1431.     X    ** so that failed articles (if any) go to the end
  1432.     X    ** of the new file.
  1433.     X    */
  1434.     X    if (!feof(Qfp)) {
  1435.     X        dprintf(stderr, "%s: copying the unused portion of %s to %s\n",
  1436.     X            Pname, Qfile, tempfile);
  1437.     X        while(fgets(buf, sizeof(buf), Qfp) != (char *)NULL)
  1438.     X            (void) fputs(buf, tmpfp);
  1439.     X    }
  1440.     X
  1441.     X    /*
  1442.     X    ** Here we write out the filenames of articles which
  1443.     X    ** failed at the remote end.
  1444.     X    */
  1445.     X    dprintf(stderr, "%s: writing failed article filenames to %s\n",
  1446.     X        Pname, tempfile);
  1447.     X    L_LOOP(lp, FailedArticles) {
  1448.     X        fprintf(tmpfp, "%s\n", lp->l_item);
  1449.     X        nart++;
  1450.     X    }
  1451.     X    dprintf(stderr, "%s: wrote %d article filenames to %s\n",
  1452.     X        Pname, nart, tempfile);
  1453.     X
  1454.     X    (void) fflush(tmpfp);
  1455.     X    /*
  1456.     X    ** If writing the temp file failed (maybe /tmp is full?)
  1457.     X    ** back out and leave the queue file exactly as it is.
  1458.     X    */
  1459.     X    if (ferror(tmpfp)) {
  1460.     X        sprintf(buf, "rewrite(): copy to %s failed", tempfile);
  1461.     X        log(L_WARNING, buf);
  1462.     X        (void) fclose(tmpfp);
  1463.     X        FCLOSE(Qfp);
  1464.     X        if (unlink(tempfile) < 0) {
  1465.     X            sprintf(buf, E_unlk, tempfile, errmsg(errno));
  1466.     X            log(L_WARNING, buf);
  1467.     X        }
  1468.     X        requeue((char *)NULL,(char *)NULL);    /* reset */
  1469.     X        return;
  1470.     X    }
  1471.     X
  1472.     X    rewind(tmpfp);
  1473.     X#ifdef    FTRUNCATE
  1474.     X    rewind(Qfp);
  1475.     X    if (ftruncate(fileno(Qfp), (off_t)0) < 0) {
  1476.     X        sprintf(buf, "ftruncate(%s, 0): %s", Qfile, errmsg(errno));
  1477.     X        log(L_WARNING, buf);
  1478.     X        FCLOSE(Qfp);
  1479.     X        (void) fclose(tmpfp);
  1480.     X        if (unlink(tempfile) < 0) {
  1481.     X            sprintf(buf, E_unlk, tempfile, errmsg(errno));
  1482.     X            log(L_WARNING, buf);
  1483.     X        }
  1484.     X        requeue((char *)NULL,(char *)NULL);    /* reset */
  1485.     X        return;
  1486.     X    }
  1487.     X#else
  1488.     X    FCLOSE(Qfp);    /* we just nuked our lock here (lockfd) */
  1489.     X    if ((Qfp = fopen(Qfile, mode)) == (FILE *)NULL) {
  1490.     X        sprintf(buf, E_fopen, Qfile, mode, errmsg(errno));
  1491.     X        log(L_WARNING, buf);
  1492.     X        (void) fclose(tmpfp);
  1493.     X        if (unlink(tempfile) < 0) {
  1494.     X            sprintf(buf, E_unlk, tempfile, errmsg(errno));
  1495.     X            log(L_WARNING, buf);
  1496.     X        }
  1497.     X        requeue((char *)NULL,(char *)NULL);    /* reset */
  1498.     X        return;
  1499.     X    }
  1500.     X    /* Try to get our lock back (but continue whether we do or not) */
  1501.     X    (void) lockfd(fileno(Qfp), Qfile, DONT_BLOCK);
  1502.     X#endif    /* FTRUNCATE */
  1503.     X
  1504.     X    dprintf(stderr, "%s: copying %s back to %s\n", Pname, tempfile, Qfile);
  1505.     X    while(fgets(buf, sizeof(buf), tmpfp) != (char *)NULL)
  1506.     X        (void) fputs(buf, Qfp);
  1507.     X
  1508.     X    (void) fflush(Qfp);
  1509.     X    if (ferror(Qfp)) {
  1510.     X        sprintf(buf, "rewrite(): copy to %s failed", Qfile);
  1511.     X        log(L_WARNING, buf);
  1512.     X    }
  1513.     X    (void) fclose(tmpfp);
  1514.     X    FCLOSE(Qfp);
  1515.     X    if (unlink(tempfile) < 0) {
  1516.     X        sprintf(buf, E_unlk, tempfile, errmsg(errno));
  1517.     X        log(L_WARNING, buf);
  1518.     X    }
  1519.     X    requeue((char *)NULL,(char *)NULL);        /* reset */
  1520.     X    dprintf(stderr, "%s: rewrite(%s): done\n", Pname, Qfile);
  1521.     X    return;
  1522.     X}
  1523.     X
  1524.     X/*
  1525.     X** Signal stuff
  1526.     X**
  1527.     X** There's probably too much stuff to do in this signal
  1528.     X** handler, but we're going to exit anyway...
  1529.     X*/
  1530.     Xinterrupted(sig)
  1531.     Xint    sig;
  1532.     X{
  1533.     X    char buf[BUFSIZ];
  1534.     X
  1535.     X#ifndef RELSIG
  1536.     X    catchsig(SIG_IGN);    /* for System V - hope we're quick enough */
  1537.     X#endif    /* RELSIG */
  1538.     X    sprintf(buf, "%s signal %d", Host, sig);
  1539.     X    log(L_NOTICE, buf);
  1540.     X    requeue(Article,(char *)NULL);
  1541.     X    cleanup();
  1542.     X    if (Report_Stats)
  1543.     X        logstats();
  1544.     X    goodbye(DONT_WAIT);
  1545.     X    exit(EX_TEMPFAIL);
  1546.     X}
  1547.     X
  1548.     Xstruct {
  1549.     X    int    signo;
  1550.     X    ifunp    state;
  1551.     X} SigList[] = {
  1552.     X    {SIGHUP},
  1553.     X    {SIGINT},
  1554.     X    {SIGQUIT},
  1555.     X    {SIGTERM},
  1556.     X    {NULL}
  1557.     X};
  1558.     X
  1559.     XSIGRET
  1560.     Xcatchsig(handler)
  1561.     Xifunp    handler;
  1562.     X{
  1563.     X    register int    i;
  1564.     X
  1565.     X    if (handler != SIG_IGN) {
  1566.     X        for(i = 0; SigList[i].signo != NULL; i++) {
  1567.     X            SigList[i].state = signal(SigList[i].signo, handler);
  1568.     X        }
  1569.     X    } else {
  1570.     X        for(i = 0; SigList[i].signo != NULL; i++) {
  1571.     X            (void) signal(SigList[i].signo, handler);
  1572.     X        }
  1573.     X    }
  1574.     X}
  1575.     X
  1576.     Xvoid
  1577.     Xrestsig()
  1578.     X{
  1579.     X    register int    i;
  1580.     X
  1581.     X    for(i = 0; SigList[i].signo != NULL; i++) {
  1582.     X        if (SigList[i].state != (ifunp)(-1))
  1583.     X            (void) signal(SigList[i].signo, SigList[i].state);
  1584.     X    }
  1585.     X}
  1586.     X
  1587.     X/*
  1588.     X** log stuff
  1589.     X*/
  1590.     Xvoid
  1591.     Xlog(importance, error)
  1592.     Xint    importance;
  1593.     Xchar    *error;
  1594.     X{
  1595.     X    int skip = FALSE;
  1596.     X    FILE    *report = (importance == L_INFO ? stdout : stderr);
  1597.     X    fprintf(report, "%s: %s\n", Pname, error);
  1598.     X#ifdef    SYSLOG 
  1599.     X    switch(importance) {
  1600.     X#ifdef LOG
  1601.     X    case L_DEBUG:    importance = LOG_DEBUG;        break;
  1602.     X#else
  1603.     X    case L_DEBUG:    skip = TRUE;            break;
  1604.     X#endif
  1605.     X    case L_INFO:    importance = LOG_INFO;        break;
  1606.     X    case L_NOTICE:    importance = LOG_NOTICE;    break;
  1607.     X    case L_WARNING:    importance = LOG_WARNING;    break;
  1608.     X    default:    importance = LOG_DEBUG;        break;
  1609.     X    }
  1610.     X    if (skip == FALSE) syslog(importance, error);
  1611.     X#endif    /* SYSLOG */
  1612.     X}
  1613.     X
  1614.     X/*
  1615.     X** Lock a file descriptor
  1616.     X**
  1617.     X** NOTE: if the appropriate system calls are unavailable,
  1618.     X** this subroutine is a no-op.
  1619.     X*/
  1620.     Xlockfd(fd, file, non_blocking)
  1621.     Xint    fd, non_blocking;
  1622.     Xchar    *file;            /* just for error reporting */
  1623.     X{
  1624.     X    char    buf[BUFSIZ];
  1625.     X#ifdef    USG
  1626.     X#ifdef    F_TLOCK
  1627.     X    if (lockf(fd, (non_blocking ? F_TLOCK : F_LOCK), 0) < 0) {
  1628.     X        if (errno != EACCES) {
  1629.     X            sprintf(buf, "lockf(%s): %s\n", file, errmsg(errno));
  1630.     X            log(L_WARNING, buf);
  1631.     X        }
  1632.     X        return(FALSE);
  1633.     X    }
  1634.     X#endif    /* F_TLOCK */
  1635.     X#else
  1636.     X#ifdef    LOCK_EX
  1637.     X    if (flock(fd, LOCK_EX|(non_blocking ? LOCK_NB : 0)) < 0) {
  1638.     X        if (errno != EWOULDBLOCK) {
  1639.     X            sprintf(buf, "flock(%s): %s\n", file, errmsg(errno));
  1640.     X            log(L_WARNING, buf);
  1641.     X        }
  1642.     X        return(FALSE);
  1643.     X    }
  1644.     X#endif    /* LOCK_EX */
  1645.     X#endif    /* USG */
  1646.     X    return(TRUE);
  1647.     X}
  1648. SHAR_EOF
  1649. if test 27564 -ne "`wc -c < 'nntpxmit.c'`"
  1650. then
  1651.     echo shar: error transmitting "'nntpxmit.c'" '(should have been 27564 characters)'
  1652. fi
  1653. echo shar: extracting "'remote.c'" '(10680 characters)'
  1654. sed 's/^    X//' << \SHAR_EOF > 'remote.c'
  1655.     X#ifndef lint
  1656.     Xstatic char * rcsid = "@(#)$Header: remote.c,v 1.6 91/03/19 03:03:28 sob Exp $";
  1657.     X#endif
  1658.     X/*
  1659.     X** remote communication routines for NNTP/SMTP style communication.
  1660.     X**
  1661.     X************
  1662.     X** This version has been modified to support mmap()'ing of article files
  1663.     X** on systems that support it.
  1664.     X**
  1665.     X** David Robinson (david@elroy.jpl.nasa.gov) and
  1666.     X** Steve Groom (stevo@elroy.jpl.nasa.gov), June 30, 1989.
  1667.     X**
  1668.     X************
  1669.     X**
  1670.     X**    sendcmd        - return TRUE on error.
  1671.     X**
  1672.     X**    readreply    - return reply code or FAIL for error;
  1673.     X**                modifies buffer passed to it.
  1674.     X**
  1675.     X**    converse    - sendcmd() & readreply();
  1676.     X**                return reply code or FAIL for error;
  1677.     X**                modifies buffer passed to it.
  1678.     X**
  1679.     X**    hello        - establish connection with remote;
  1680.     X**                check greeting code.
  1681.     X**
  1682.     X**    goodbye        - give QUIT command, and shut down connection.
  1683.     X**
  1684.     X**    sfgets        - safe fgets(); does fgets with TIMEOUT.
  1685.     X**              (N.B.: possibly unportable stdio macro ref in here)
  1686.     X**
  1687.     X**    rfgets        - remote fgets() (calls sfgets());
  1688.     X**                does SMTP dot escaping and
  1689.     X**                \r\n -> \n conversion.
  1690.     X**
  1691.     X**    sendfile    - send a file with SMTP dot escaping and
  1692.     X**                \n -> \r\n conversion.
  1693.     X**
  1694.     X** Erik E. Fair <fair@ucbarpa.berkeley.edu>
  1695.     X*/
  1696.     X#include "../common/conf.h"
  1697.     X#include "nntpxmit.h"
  1698.     X#include <sys/types.h>
  1699.     X#include <sys/socket.h>
  1700.     X#include <errno.h>
  1701.     X#ifdef LAI_TCP
  1702.     X#include <net/errno.h>
  1703.     X#endif
  1704.     X#include <stdio.h>
  1705.     X#include <ctype.h>
  1706.     X#include <setjmp.h>
  1707.     X#include <signal.h>
  1708.     X#ifdef dgux
  1709.     X#define _IOERR  _IO_ERR
  1710.     X#endif
  1711.     X#ifdef SYSLOG
  1712.     X#ifdef FAKESYSLOG
  1713.     X#include "../server/fakesyslog.h"
  1714.     X#else
  1715.     X#include <syslog.h>
  1716.     X#endif
  1717.     X#endif
  1718.     X#include "get_tcp_conn.h"
  1719.     X#include "../common/nntp.h"
  1720.     X
  1721.     Xstatic    jmp_buf    SFGstack;
  1722.     XFILE    *rmt_rd;
  1723.     XFILE    *rmt_wr;
  1724.     Xchar    *sfgets();
  1725.     Xchar    *rfgets();
  1726.     X
  1727.     Xextern    int    errno;
  1728.     Xextern    char    Debug;
  1729.     Xextern    char    *errmsg();
  1730.     Xextern    char    *strcpy();
  1731.     Xextern    void    log();
  1732.     X
  1733.     X/*
  1734.     X** send cmd to remote, terminated with a CRLF.
  1735.     X*/
  1736.     Xsendcmd(cmd)
  1737.     Xchar    *cmd;
  1738.     X{
  1739.     X    if (cmd == (char *)NULL)
  1740.     X        return(TRUE);    /* error */
  1741.     X    dprintf(stderr, ">>> %s\n", cmd);    /* DEBUG */
  1742.     X    (void) fprintf(rmt_wr, "%s\r\n", cmd);
  1743.     X    (void) fflush(rmt_wr);
  1744.     X    return(ferror(rmt_wr));
  1745.     X}
  1746.     X
  1747.     X/*
  1748.     X** read a reply line from the remote server and return the code number
  1749.     X** as an integer, and the message in a buffer supplied by the caller.
  1750.     X** Returns FAIL if something went wrong.
  1751.     X*/
  1752.     Xreadreply(buf, size)
  1753.     Xregister char    *buf;
  1754.     Xint    size;
  1755.     X{
  1756.     X    register char    *cp;
  1757.     X    register int    len;
  1758.     X
  1759.     X    if (buf == (char *)NULL || size <= 0)
  1760.     X        return(FAIL);
  1761.     X
  1762.     X    /*
  1763.     X    ** make sure it's invalid, unless we say otherwise
  1764.     X    */
  1765.     X    buf[0] = '\0';
  1766.     X
  1767.     X    /*
  1768.     X    ** read one line from the remote
  1769.     X    */
  1770.     X    if (sfgets(buf, size, rmt_rd) == NULL)
  1771.     X        return(FAIL);    /* error reading from remote */
  1772.     X
  1773.     X    /*
  1774.     X    ** Make sure that what the remote sent us had a CRLF at the end
  1775.     X    ** of the line, and then null it out.
  1776.     X    */
  1777.     X    if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r' &&
  1778.     X        *(cp + 1) == '\n')
  1779.     X    {
  1780.     X        *cp = '\0';
  1781.     X    } else
  1782.     X        return(FAIL);    /* error reading from remote */
  1783.     X
  1784.     X    dprintf(stderr, "%s\n", buf);    /* DEBUG */
  1785.     X    /*
  1786.     X    ** Skip any non-digits leading the response code 
  1787.     X    ** and then convert the code from ascii to integer for
  1788.     X    ** return from this routine.
  1789.     X    */
  1790.     X    cp = buf;
  1791.     X    while(*cp != '\0' && isascii(*cp) && !isdigit(*cp))
  1792.     X        cp++;    /* skip anything leading */
  1793.     X
  1794.     X    if (*cp == '\0' || !isascii(*cp))
  1795.     X        return(FAIL);    /* error reading from remote */
  1796.     X
  1797.     X    return(atoi(cp));
  1798.     X}
  1799.     X
  1800.     X/*
  1801.     X** send a command to the remote, and wait for a response
  1802.     X** returns the response code, and the message in the buffer
  1803.     X*/
  1804.     Xconverse(buf, size)
  1805.     Xchar    *buf;
  1806.     Xint    size;
  1807.     X{
  1808.     X    register int    resp;
  1809.     X
  1810.     X    if (sendcmd(buf))
  1811.     X        return(FAIL);    /* Ooops! Something went wrong in xmit */
  1812.     X    /*
  1813.     X    ** Skip the silly 100 series messages, since they're not the
  1814.     X    ** final response we can expect
  1815.     X    */
  1816.     X    while((resp = readreply(buf, size)) >= 100 && resp < 200)
  1817.     X        continue;
  1818.     X    return(resp);
  1819.     X}
  1820.     X
  1821.     X/*
  1822.     X** Contact the remote server and set up the two global FILE pointers
  1823.     X** to that descriptor.
  1824.     X**
  1825.     X** I can see the day when this routine will have 8 args:  one for
  1826.     X** hostname, and one for each of the seven ISO Reference Model layers
  1827.     X** for networking. A curse upon those involved with the ISO protocol
  1828.     X** effort: may they be forced to use the network that they will create,
  1829.     X** as opposed to something that works (like the Internet).
  1830.     X*/
  1831.     Xhello(host, transport)
  1832.     Xchar    *host;
  1833.     Xint    transport;
  1834.     X{ char    *service;
  1835.     X    char    *rmode = "r";
  1836.     X    char    *wmode = "w";
  1837.     X    char    *e_fdopen = "fdopen(%d, \"%s\"): %s";
  1838.     X    int    socket0, socket1;    /* to me (bad pun) */
  1839.     X    char    buf[BUFSIZ];
  1840.     X
  1841.     X    switch(transport) {
  1842.     X    case T_IP_TCP:
  1843.     X        service = "nntp";
  1844.     X        socket0 = get_tcp_conn(host, service);
  1845.     X        break;
  1846.     X    case T_DECNET:
  1847.     X#ifdef DECNET
  1848.     X        (void) signal(SIGPIPE, SIG_IGN);
  1849.     X        service = "NNTP";
  1850.     X        socket0 = dnet_conn(host, service, 0, 0, 0, 0, 0);
  1851.     X        if (socket0 < 0) {
  1852.     X            switch(errno) {
  1853.     X            case EADDRNOTAVAIL:
  1854.     X                socket0 = NOHOST;
  1855.     X                break;
  1856.     X            case ESRCH:
  1857.     X                socket0 = NOSERVICE;
  1858.     X                break;
  1859.     X            }
  1860.     X        }
  1861.     X        break;
  1862.     X#else
  1863.     X        log(L_WARNING, "no DECNET support compiled in");
  1864.     X        return(FAIL);
  1865.     X#endif
  1866.     X    case T_FD:
  1867.     X        service = "with a smile";
  1868.     X        socket0 = atoi(host);
  1869.     X        break;
  1870.     X    }
  1871.     X
  1872.     X    if (socket0 < 0) {
  1873.     X        switch(socket0) {
  1874.     X        case NOHOST:
  1875.     X            sprintf(buf, "%s host unknown", host);
  1876.     X            log(L_WARNING, buf);
  1877.     X            return(FAIL);
  1878.     X        case NOSERVICE:
  1879.     X            sprintf(buf, "%s service unknown: %s", host, service);
  1880.     X            log(L_WARNING, buf);
  1881.     X            return(FAIL);
  1882.     X        case FAIL:
  1883.     X            sprintf(buf, "%s hello: %s", host, errmsg(errno));
  1884.     X            log(L_NOTICE, buf);
  1885.     X            return(FAIL);
  1886.     X        }
  1887.     X    }
  1888.     X
  1889.     X    if ((socket1 = dup(socket0)) < 0) {
  1890.     X        sprintf(buf, "dup(%d): %s", socket0, errmsg(errno));
  1891.     X        log(L_WARNING, buf);
  1892.     X        (void) close(socket0);
  1893.     X        return(FAIL);
  1894.     X    }
  1895.     X
  1896.     X    if ((rmt_rd = fdopen(socket0, rmode)) == (FILE *)NULL) {
  1897.     X        sprintf(buf, e_fdopen, socket0, rmode);
  1898.     X        log(L_WARNING, buf);
  1899.     X        (void) close(socket0);
  1900.     X        (void) close(socket1);
  1901.     X        return(FAIL);
  1902.     X    }
  1903.     X
  1904.     X    if ((rmt_wr = fdopen(socket1, wmode)) == (FILE *)NULL) {
  1905.     X        sprintf(buf, e_fdopen, socket1, wmode);
  1906.     X        log(L_WARNING, buf);
  1907.     X        (void) fclose(rmt_rd);
  1908.     X        rmt_rd = (FILE *)NULL;
  1909.     X        (void) close(socket1);
  1910.     X        return(FAIL);
  1911.     X    }
  1912.     X
  1913.     X    switch(readreply(buf, sizeof(buf))) {
  1914.     X    case OK_CANPOST:
  1915.     X    case OK_NOPOST:
  1916.     X        if (ferror(rmt_rd)) {
  1917.     X            goodbye(DONT_WAIT);
  1918.     X            return(FAIL);
  1919.     X        }
  1920.     X        break;
  1921.     X    default:
  1922.     X        if (buf[0] != '\0') {
  1923.     X            char    err[BUFSIZ];
  1924.     X
  1925.     X            sprintf(err, "%s greeted us with %s", host, buf);
  1926.     X            log(L_NOTICE, err);
  1927.     X        }
  1928.     X        goodbye(DONT_WAIT);
  1929.     X        return(FAIL);
  1930.     X    }
  1931.     X    return(NULL);
  1932.     X}
  1933.     X
  1934.     X/*
  1935.     X** Say goodbye to the nice remote server.
  1936.     X**
  1937.     X** We trap SIGPIPE because the socket might already be gone.
  1938.     X*/
  1939.     Xgoodbye(wait_for_reply)
  1940.     Xint    wait_for_reply;
  1941.     X{
  1942.     X    register ifunp    pstate = signal(SIGPIPE, SIG_IGN);
  1943.     X
  1944.     X    if (sendcmd("QUIT"))
  1945.     X        wait_for_reply = FALSE;    /* override, something's wrong. */
  1946.     X    /*
  1947.     X    ** I don't care what they say to me; this is just being polite.
  1948.     X    */
  1949.     X    if (wait_for_reply) {
  1950.     X        char    buf[BUFSIZ];
  1951.     X
  1952.     X        (void) readreply(buf, sizeof(buf));
  1953.     X    }
  1954.     X    (void) fclose(rmt_rd);
  1955.     X    rmt_rd = (FILE *)NULL;
  1956.     X    (void) fclose(rmt_wr);
  1957.     X    rmt_wr = (FILE *)NULL;
  1958.     X    if (pstate != (ifunp)(-1))
  1959.     X        (void) signal(SIGPIPE, pstate);
  1960.     X}
  1961.     X
  1962.     Xstatic SIGRET
  1963.     Xto_sfgets()
  1964.     X{
  1965.     X    longjmp(SFGstack, 1);
  1966.     X}
  1967.     X
  1968.     X/*
  1969.     X** `Safe' fgets, ala sendmail. This fgets will timeout after some
  1970.     X** period of time, on the assumption that if the remote did not
  1971.     X** return, they're gone.
  1972.     X** WARNING: contains a possibly unportable reference to stdio
  1973.     X** error macros.
  1974.     X*/
  1975.     Xchar *
  1976.     Xsfgets(buf, size, fp)
  1977.     Xchar    *buf;
  1978.     Xint    size;
  1979.     XFILE    *fp;
  1980.     X{
  1981.     X    register char    *ret;
  1982.     X    int    esave;
  1983.     X
  1984.     X    if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
  1985.     X        return((char *)NULL);
  1986.     X    if (setjmp(SFGstack)) {
  1987.     X        (void) alarm(0);        /* reset alarm clock */
  1988.     X        (void) signal(SIGALRM, SIG_DFL);
  1989.     X#ifdef apollo
  1990.     X        fp->_flag |= _SIERR;
  1991.     X#else
  1992.     X        fp->_flag |= _IOERR;        /* set stdio error */
  1993.     X#endif
  1994.     X#ifndef ETIMEDOUT
  1995.     X        errno = EPIPE;            /* USG doesn't have ETIMEDOUT*/
  1996.     X#else
  1997.     X        errno = ETIMEDOUT;        /* connection timed out */
  1998.     X#endif
  1999.     X        return((char *)NULL);        /* bad read, remote time out */
  2000.     X    }
  2001.     X    (void) signal(SIGALRM, to_sfgets);
  2002.     X    (void) alarm(TIMEOUT);
  2003.     X    ret = fgets(buf, size, fp);
  2004.     X    esave = errno;
  2005.     X    (void) alarm(0);            /* reset alarm clock */
  2006.     X    (void) signal(SIGALRM, SIG_DFL);    /* reset SIGALRM */
  2007.     X    errno = esave;
  2008.     X    return(ret);
  2009.     X}
  2010.     X
  2011.     X/*
  2012.     X** Remote fgets - converts CRLF to \n, and returns NULL on `.' EOF from
  2013.     X** the remote. Otherwise it returns its first argument, like fgets(3).
  2014.     X*/
  2015.     Xchar *
  2016.     Xrfgets(buf, size, fp)
  2017.     Xchar    *buf;
  2018.     Xint    size;
  2019.     XFILE    *fp;
  2020.     X{
  2021.     X    register char    *cp = buf;
  2022.     X    register int    len;
  2023.     X
  2024.     X    if (buf == (char *)NULL || size <= 0 || fp == (FILE *)NULL)
  2025.     X        return((char *)NULL);
  2026.     X    *cp = '\0';
  2027.     X    if (sfgets(buf, size, fp) == (char *)NULL)
  2028.     X        return((char *)NULL);
  2029.     X
  2030.     X    /* <CRLF> => '\n' */
  2031.     X    if ((len = strlen(buf)) > 2 && *(cp = &buf[len - 2]) == '\r') {
  2032.     X        *cp++ = '\n';
  2033.     X        *cp = '\0';
  2034.     X    }
  2035.     X
  2036.     X    /* ".\n" => EOF */
  2037.     X    cp = buf;
  2038.     X    if (*cp++ == '.' && *cp == '\n') {
  2039.     X        return((char *)NULL);    /* EOF */
  2040.     X    }
  2041.     X
  2042.     X    /* Dot escaping */
  2043.     X    if (buf[0] == '.')
  2044.     X        (void) strcpy(&buf[0], &buf[1]);
  2045.     X    return(buf);
  2046.     X}
  2047.     X
  2048.     X/*
  2049.     X** send the contents of an open file descriptor to the remote,
  2050.     X** with appropriate RFC822 filtering (e.g. CRLF line termination,
  2051.     X** and dot escaping). Return FALSE if something went wrong.
  2052.     X*/
  2053.     Xsendfile(fp)
  2054.     XFILE    *fp;
  2055.     X{
  2056.     X    register int    c;
  2057.     X    register FILE    *remote = rmt_wr;
  2058.     X    register int    nl = TRUE;    /* assume we start on a new line */
  2059.     X
  2060.     X#ifdef MMAP
  2061.     X    register char *mbufr,*mptr;
  2062.     X        long msize;
  2063.     X        long offset;
  2064.     X        struct stat sbuf;
  2065.     X    char buf[BUFSIZ];
  2066.     X#endif MMAP
  2067.     X
  2068.     X/*
  2069.     X** I'm using putc() instead of fputc();
  2070.     X** why do a subroutine call when you don't have to?
  2071.     X** Besides, this ought to give the C preprocessor a work-out.
  2072.     X*/
  2073.     X#ifdef MMAP
  2074.     X#define    PUTC(c)    if (putc(c, remote) == EOF) {\
  2075.     X    (void) munmap (mbufr, sbuf.st_size);\
  2076.     X    return(FALSE); }
  2077.     X#else !MMAP
  2078.     X#define    PUTC(c)    if (putc(c, remote) == EOF) return(FALSE)
  2079.     X#endif !MMAP
  2080.     X
  2081.     X    if (fp == (FILE *)NULL)
  2082.     X        return(FALSE);
  2083.     X
  2084.     X#ifdef MMAP
  2085.     X    /* map the article into memory */
  2086.     X    (void) fstat(fileno(fp), &sbuf);
  2087.     X        mbufr = mmap (0, sbuf.st_size, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
  2088.     X        if(mbufr == (char *) -1){
  2089.     X        sprintf(buf, "sendfile: mmap failed: %s", errmsg(errno));
  2090.     X        log(L_NOTICE, buf);
  2091.     X                return(FALSE);
  2092.     X        }
  2093.     X
  2094.     X        mptr = mbufr;        /* start of article in memory */
  2095.     X        msize = sbuf.st_size;    /* size of article (bytes) */
  2096.     X    while(msize-- > 0) {
  2097.     X        c = *mptr++;
  2098.     X#else !MMAP
  2099.     X    /*
  2100.     X    ** the second test makes no sense to me,
  2101.     X    ** but System V apparently needed it...
  2102.     X    */
  2103.     X    while((c = fgetc(fp)) != EOF && !feof(fp)) {
  2104.     X#endif !MMAP
  2105.     X        switch(c) {
  2106.     X        case '\177':            /* skip deletes... */
  2107.     X            break;
  2108.     X        case '\n':
  2109.     X            PUTC('\r');        /* \n -> \r\n */
  2110.     X            PUTC(c);
  2111.     X            nl = TRUE;        /* for dot escaping */
  2112.     X            break;
  2113.     X        case '.':
  2114.     X            if (nl) {
  2115.     X                PUTC(c);    /* add a dot */
  2116.     X                nl = FALSE;
  2117.     X            }
  2118.     X            PUTC(c);
  2119.     X            break;
  2120.     X        default:
  2121.     X            PUTC(c);
  2122.     X            nl = FALSE;
  2123.     X            break;
  2124.     X        }
  2125.     X    }
  2126.     X    if (!nl) {
  2127.     X        PUTC('\r');
  2128.     X        PUTC('\n');
  2129.     X    }
  2130.     X#ifdef MMAP
  2131.     X    (void) munmap (mbufr, sbuf.st_size);
  2132.     X#endif MMAP
  2133.     X    return( !(sendcmd(".") || ferror(fp)) );
  2134.     X}
  2135. SHAR_EOF
  2136. if test 10680 -ne "`wc -c < 'remote.c'`"
  2137. then
  2138.     echo shar: error transmitting "'remote.c'" '(should have been 10680 characters)'
  2139. fi
  2140. echo "Done with directory 'xmit'"
  2141. cd ..
  2142. fi
  2143. if test -d 'xfer'
  2144. then
  2145. echo "Entering directory 'xfer'"
  2146. cd xfer
  2147. echo shar: extracting "'nntpxfer.c'" '(12837 characters)'
  2148. sed 's/^    X//' << \SHAR_EOF > 'nntpxfer.c'
  2149.     X#ifndef lint
  2150.     Xstatic char * scsid = "@(#)$Header: nntpxfer.c,v 1.10 91/03/19 03:03:45 sob Exp $";
  2151.     X#endif
  2152.     X/*
  2153.     X * nntpxfer
  2154.     X *
  2155.     X * Connects to the specified nntp server, and transfers all new news
  2156.     X * since the last successful invocation.
  2157.     X *
  2158.     X * last successful invocation date and time are stored in a file at
  2159.     X * /usr/spool/news/nntp.<hostname> as 
  2160.     X *    groups YYMMDD HHMMSS distributions\n
  2161.     X * in case you need to edit it.  You can also override this on 
  2162.     X * the command line in the same format, in which case the file won't
  2163.     X * be updated.
  2164.     X *
  2165.     X *    Brian Kantor, UCSD 1986
  2166.     X * (some bug fixes by ambar@athena.mit.edu)
  2167.     X * Modified to use NNTP distribution conf.h file and nntpxmit's get_tcp_conn.c
  2168.     X * subroutines so that nntpxfer could be used on more systems.
  2169.     X * Stan Barber, November 7, 1989 <sob@bcm.tmc.edu>
  2170.     X *
  2171.     X */
  2172.     X
  2173.     X#include "../common/conf.h"
  2174.     X#ifdef DEBUG
  2175.     X#undef SYSLOG
  2176.     X#endif
  2177.     X
  2178.     X#include <sys/types.h>
  2179.     X#ifdef LAI_TCP
  2180.     X#include <sys/bsdtypes.h>
  2181.     X#endif
  2182.     X#ifdef NDIR
  2183.     X#ifdef M_XENIX
  2184.     X#include <sys/ndir.h>
  2185.     X#else
  2186.     X#include <ndir.h>
  2187.     X#endif
  2188.     X#else
  2189.     X#include <sys/dir.h>
  2190.     X#endif
  2191.     X#ifdef USG
  2192.     X#include <time.h>
  2193.     X#else
  2194.     X#include <sys/time.h>
  2195.     X#endif
  2196.     X
  2197.     X#include <stdio.h>
  2198.     X#include <errno.h>
  2199.     X#include <ctype.h>
  2200.     X#include <setjmp.h>
  2201.     X#ifndef NONETDB
  2202.     X#include <netdb.h>
  2203.     X#endif
  2204.     X#include <signal.h>
  2205.     X#ifdef SYSLOG
  2206.     X#ifdef FAKESYSLOG
  2207.     X#include "../server/fakesyslog.h"
  2208.     X#else
  2209.     X#include <syslog.h>
  2210.     X#endif
  2211.     X#endif
  2212.     X
  2213.     X#ifdef DBM
  2214.     X# ifdef DBZ
  2215.     X#   include <dbz.h>
  2216.     X#else /* DBZ */
  2217.     X# undef NULL
  2218.     X# include <dbm.h>
  2219.     X# undef NULL
  2220.     X# define NULL    0
  2221.     X#endif /* DBZ */
  2222.     X#endif  /* DBM */
  2223.     X
  2224.     X#ifdef NDBM
  2225.     X#include <ndbm.h>
  2226.     X#include <fcntl.h>
  2227.     Xstatic DBM *db = NULL;
  2228.     X#endif
  2229.     X#ifndef TIMEOUT
  2230.     X#define TIMEOUT (30*60)
  2231.     X#endif
  2232.     X#ifndef MAX_ARTICLES
  2233.     X#define MAX_ARTICLES 4096
  2234.     X#endif
  2235.     X
  2236.     Xchar    *malloc();
  2237.     Xchar    *strcpy();
  2238.     Xchar    *strcat();
  2239.     Xchar    *rindex();
  2240.     Xlong    time();
  2241.     Xu_long    inet_addr();
  2242.     X
  2243.     Xextern int errno;
  2244.     Xchar *artlist[MAX_ARTICLES];
  2245.     Xint server;            /* stream socket to the nntp server */
  2246.     XFILE * rd_fp, * wr_fp;
  2247.     Xint newart, dupart, misart;
  2248.     Xchar * Pname;
  2249.     X
  2250.     Xmain(argc, argv)
  2251.     Xint argc;
  2252.     Xchar *argv[];
  2253.     X{
  2254.     X    FILE *dtfile;        /* where last xfer date/time stored */
  2255.     X    char buf[BUFSIZ];
  2256.     X    char lastdate[16];
  2257.     X    char distributions[BUFSIZ];
  2258.     X    char dtname[128];
  2259.     X    char newsgroups[BUFSIZ];
  2260.     X    char lasttime[16];
  2261.     X    int i;
  2262.     X    int omitupdate = 0;        /* 1 = don't update datetime */
  2263.     X    long clock;
  2264.     X    long newdate, newtime;
  2265.     X    struct tm *now;
  2266.     X    Pname = ((Pname = rindex(argv[0], '/')) ? Pname + 1 : argv[0]);
  2267.     X    /* OPTIONS
  2268.     X        argv[1] MUST be the host name
  2269.     X        argv[2-4] MAY be "newsgroups YYMMDD HHMMSS"
  2270.     X            argv[5] MAY be distributions
  2271.     X        (otherwise use 2-4/5 from the file
  2272.     X        "/usr/spool/news/nntp.hostname")
  2273.     X    */
  2274.     X
  2275.     X    if (argc != 2 && argc != 5 && argc != 6)
  2276.     X        {
  2277.     X        (void) printf("Usage: %s host [groups YYMMDD HHMMSS [<dist>]]\n",
  2278.     X            argv[0]);
  2279.     X        exit(1);
  2280.     X        }
  2281.     X    
  2282.     X    if (argc > 2)
  2283.     X        {
  2284.     X        omitupdate=1;
  2285.     X        (void) strcpy(newsgroups, argv[2]);
  2286.     X        (void) strcpy(lastdate, argv[3]);
  2287.     X        (void) strcpy(lasttime, argv[4]);
  2288.     X        (void) strcpy(distributions, "");
  2289.     X        if (argc > 5)
  2290.     X            (void) strcpy(distributions, argv[5]);
  2291.     X        }
  2292.     X    else
  2293.     X        {
  2294.     X        (void) sprintf(dtname, "%s/nntp.%s",SPOOLDIR,argv[1]);
  2295.     X        dtfile = fopen(dtname, "r");
  2296.     X        if (dtfile == (FILE *) 0)
  2297.     X            {
  2298.     X            (void) printf("%s not found; using * 860101 000000 \n", 
  2299.     X                dtname);
  2300.     X            (void) strcpy(newsgroups, "*");
  2301.     X            (void) strcpy(lastdate, "860101");
  2302.     X            (void) strcpy(lasttime, "000000");
  2303.     X            (void) strcpy(distributions, "");
  2304.     X            }
  2305.     X        else
  2306.     X            {
  2307.     X            if (fscanf(dtfile, "%s %s %s %s",
  2308.     X                newsgroups, lastdate, lasttime, distributions) < 3)
  2309.     X                {
  2310.     X                (void) printf("%s invalid; using * 860101 000000\n",
  2311.     X                    dtname);
  2312.     X                (void) strcpy(newsgroups, "*");
  2313.     X                (void) strcpy(lastdate, "860101");
  2314.     X                (void) strcpy(lasttime, "000000");
  2315.     X                (void) strcpy(distributions, "");
  2316.     X                }
  2317.     X            (void) fclose(dtfile);
  2318.     X            }
  2319.     X        clock = time((long *)0);
  2320.     X        now = gmtime(&clock);
  2321.     X        newdate = (now->tm_year * 10000) +
  2322.     X            ((now->tm_mon + 1) * 100) + now->tm_mday;
  2323.     X        newtime = (now->tm_hour * 10000) +
  2324.     X            (now->tm_min * 100) + now->tm_sec;
  2325.     X#ifdef DEBUG
  2326.     X    printf("server is %s\n",argv[1]);
  2327.     X    printf("lastdate is %s\n",lastdate);
  2328.     X    printf("lasttime is %s\n",lasttime);
  2329.     X    printf("newsgroups is '%s'\n",newsgroups);
  2330.     X    printf("distributions is '%s'\n",distributions);
  2331.     X#endif
  2332.     X        }
  2333.     X#ifdef SYSLOG
  2334.     X#ifdef BSD_42
  2335.     X    openlog("nntpxfer", LOG_PID);
  2336.     X#else
  2337.     X    openlog("nntpxfer", LOG_PID, SYSLOG);
  2338.     X#endif
  2339.     X#endif
  2340.     X
  2341.     X#ifdef DBM
  2342.     X    if (dbminit(HISTORY_FILE) < 0)
  2343.     X        {
  2344.     X#ifdef SYSLOG
  2345.     X        syslog(LOG_ERR,"couldn't open history file: %m");
  2346.     X#else
  2347.     X        perror("nntpxfer: couldn't open history file");
  2348.     X#endif
  2349.     X        exit(1);
  2350.     X        }
  2351.     X#endif
  2352.     X#ifdef NDBM
  2353.     X     if ((db = dbm_open(HISTORY_FILE, O_RDONLY, 0)) == NULL) 
  2354.     X         {
  2355.     X#ifdef SYSLOG
  2356.     X         syslog(LOG_ERR,"couldn't open history file: %m");
  2357.     X#else
  2358.     X         perror("nntpxfer: couldn't open history file");
  2359.     X#endif
  2360.     X         exit(1);
  2361.     X         }
  2362.     X#endif
  2363.     X    if ((server = get_tcp_conn(argv[1],"nntp")) < 0) 
  2364.     X        {
  2365.     X#ifdef SYSLOG
  2366.     X        syslog(LOG_ERR,"could not open socket: %m");
  2367.     X#else
  2368.     X        perror("nntpxfer: could not open socket");
  2369.     X#endif
  2370.     X        exit(1);
  2371.     X        }
  2372.     X    if ((rd_fp = fdopen(server,"r")) == (FILE *) 0){
  2373.     X#ifdef SYSLOG
  2374.     X        syslog(LOG_ERR,"could not fdopen socket: %m");
  2375.     X#else
  2376.     X        perror("nntpxfer: could not fdopen socket");
  2377.     X#endif
  2378.     X        exit(1);
  2379.     X        }
  2380.     X
  2381.     X#ifdef SYSLOG
  2382.     X    syslog(LOG_DEBUG,"connected to nntp server at %s", argv[1]);
  2383.     X#endif
  2384.     X#ifdef DEBUG
  2385.     X    printf("connected to nntp server at %s\n", argv[1]);
  2386.     X#endif
  2387.     X    /*
  2388.     X    * ok, at this point we're connected to the nntp daemon 
  2389.     X    * at the distant host.
  2390.     X    */
  2391.     X    /* get the greeting herald */
  2392.     X    (void) sockread(buf);
  2393.     X#ifdef DEBUG
  2394.     X    (void) printf("%s\n", buf);
  2395.     X#endif
  2396.     X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  2397.     X        {
  2398.     X#ifdef SYSLOG
  2399.     X        syslog(LOG_NOTICE,"protocol error: got '%s'\n", buf);
  2400.     X#else
  2401.     X        (void) printf("%s: protocol error: got '%s'\n", Pname,buf);
  2402.     X#endif
  2403.     X        (void) close(server);
  2404.     X        exit(1);
  2405.     X        }
  2406.     X
  2407.     X
  2408.     X    /* first, tell them we're a slave process to get priority */
  2409.     X    sockwrite("SLAVE");
  2410.     X    (void) sockread(buf);
  2411.     X#ifdef DEBUG
  2412.     X    (void) printf("%s\n", buf);
  2413.     X#endif
  2414.     X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  2415.     X        {
  2416.     X#ifdef SYSLOG
  2417.     X        syslog(LOG_NOTICE,"protocol error: got '%s'", buf);
  2418.     X#else
  2419.     X        (void) printf("%s: protocol error: got '%s'\n", Pname,buf);
  2420.     X#endif
  2421.     X        (void) close(server);
  2422.     X        exit(1);
  2423.     X        }
  2424.     X    
  2425.     X    /* now, ask for a list of new articles */
  2426.     X    if (strlen(distributions))
  2427.     X        (void) sprintf(buf,"NEWNEWS %s %s %s GMT <%s>", 
  2428.     X            newsgroups, lastdate, lasttime, distributions);
  2429.     X    else
  2430.     X        (void) sprintf(buf,"NEWNEWS %s %s %s GMT", 
  2431.     X            newsgroups, lastdate, lasttime);
  2432.     X    sockwrite(buf);
  2433.     X    (void) sockread(buf);
  2434.     X#ifdef DEBUG
  2435.     X    (void) printf("%s\n", buf);
  2436.     X#endif
  2437.     X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  2438.     X        {
  2439.     X#ifdef SYSLOG
  2440.     X        syslog(LOG_NOTICE,"protocol error: got '%s'", buf);
  2441.     X#else
  2442.     X        (void) printf("%s: protocol error: got '%s'\n", Pname,buf);
  2443.     X#endif
  2444.     X        (void) close(server);
  2445.     X        exit(1);
  2446.     X        }
  2447.     X    /* and here comes the list, terminated with a "." */
  2448.     X#ifdef DEBUG
  2449.     X    (void) printf("data\n");
  2450.     X#endif
  2451.     X    dupart = newart = 0;
  2452.     X    while (1)
  2453.     X        {
  2454.     X        (void) sockread(buf);
  2455.     X        if (!strcmp(buf,"."))
  2456.     X            break;
  2457.     X        if (wewant(buf))
  2458.     X            {
  2459.     X            if (newart >= MAX_ARTICLES)
  2460.     X                {
  2461.     X                omitupdate=1;
  2462.     X                continue;
  2463.     X                }
  2464.     X            artlist[newart] = malloc((unsigned)(strlen(buf)+1));
  2465.     X            (void) strcpy(artlist[newart], buf);
  2466.     X            newart++;
  2467.     X            }
  2468.     X        else
  2469.     X            dupart++;
  2470.     X        }
  2471.     X#ifdef DEBUG
  2472.     X    (void) printf(".\n%d new, %d dup articles\n", newart, dupart);
  2473.     X#endif
  2474.     X
  2475.     X    /* now that we know which articles we want, retrieve them */
  2476.     X    for (i=0; i < newart; i++)
  2477.     X        (void) artfetch(artlist[i]);
  2478.     X
  2479.     X#ifdef DEBUG
  2480.     X    (void) printf("%d missing articles\n", misart);
  2481.     X#endif
  2482.     X    /* we're all done, so tell them goodbye */
  2483.     X    sockwrite("QUIT");
  2484.     X    (void) sockread(buf);
  2485.     X#ifdef DEBUG
  2486.     X    (void) printf("%s\n", buf);
  2487.     X#endif
  2488.     X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  2489.     X        {
  2490.     X#ifdef SYSLOG
  2491.     X        syslog(LOG_NOTICE,"error: got '%s'", buf);
  2492.     X#else
  2493.     X        (void) printf("%s: error: got '%s'\n", Pname,buf);
  2494.     X#endif
  2495.     X        (void) close(server);
  2496.     X        exit(1);
  2497.     X        }
  2498.     X    (void) close(server);
  2499.     X
  2500.     X    /* do we want to update the timestamp file? */
  2501.     X    if (!omitupdate)
  2502.     X        {
  2503.     X        (void) sprintf(buf, "%s %06d %06d %s\n",
  2504.     X            newsgroups, newdate, newtime, distributions);
  2505.     X#ifdef DEBUG
  2506.     X        (void) printf("updating %s:\n\t%s\n", dtname, buf);
  2507.     X#endif
  2508.     X        dtfile = fopen(dtname, "w");
  2509.     X        if (dtfile == (FILE *) 0)
  2510.     X            {
  2511.     X            perror(dtname);
  2512.     X            exit(1);
  2513.     X            }
  2514.     X        (void) fputs(buf,dtfile);
  2515.     X        (void) fclose(dtfile);
  2516.     X        }
  2517.     X    exit(0);
  2518.     X}
  2519.     X
  2520.     Xartfetch(articleid)
  2521.     Xchar *articleid;
  2522.     X    {
  2523.     X#ifdef DEBUG
  2524.     X    int lines = 0;
  2525.     X#endif
  2526.     X    char buf[BUFSIZ];
  2527.     X    FILE *inews;
  2528.     X
  2529.     X    /* now, ask for the article */
  2530.     X    (void) sprintf(buf,"ARTICLE %s", articleid);
  2531.     X    sockwrite(buf);
  2532.     X    (void) sockread(buf);
  2533.     X#ifdef DEBUG
  2534.     X    (void) printf("%s\n", buf);
  2535.     X#endif
  2536.     X    if (buf[0] == '4')    /* missing article, just skipit */
  2537.     X        {
  2538.     X        misart++;
  2539.     X        return(0);
  2540.     X        }
  2541.     X
  2542.     X    if (buf[0] != '2')    /* uh-oh, something's wrong! */
  2543.     X        {
  2544.     X#ifdef SYSLOG
  2545.     X        syslog(LOG_NOTICE,"protocol error: got '%s'", buf);
  2546.     X#else
  2547.     X        (void) printf("%s: protocol error: got '%s'\n", Pname, buf);
  2548.     X#endif
  2549.     X        (void) close(server);
  2550.     X        exit(1);
  2551.     X        }
  2552.     X#ifdef DEBUG
  2553.     X    (void) printf("command: %s\n", RNEWS);
  2554.     X#endif
  2555.     X    if ( (inews = popen(RNEWS, "w")) == (FILE *) 0)
  2556.     X        {
  2557.     X        perror(RNEWS);
  2558.     X        exit(1);
  2559.     X        }
  2560.     X
  2561.     X    /* and here comes the article, terminated with a "." */
  2562.     X#ifdef DEBUG
  2563.     X    (void) printf("data\n");
  2564.     X#endif
  2565.     X    while (1)
  2566.     X        {
  2567.     X        (void) sockread(buf);
  2568.     X        if (buf[0] == '.' && buf[1] == '\0')
  2569.     X            break;
  2570.     X#ifdef DEBUG
  2571.     X        lines++;
  2572.     X#endif
  2573.     X        (void) strcat(buf,"\n");
  2574.     X        (void) fputs(((buf[0] == '.') ? buf + 1 : buf),
  2575.     X               inews);
  2576.     X        }
  2577.     X#ifdef DEBUG
  2578.     X    (void) printf(".\n%d lines\n", lines);
  2579.     X#endif
  2580.     X    (void) fflush(inews);
  2581.     X    (void) pclose(inews);
  2582.     X    return(0);
  2583.     X        }
  2584.     X
  2585.     Xstatic    jmp_buf    SFGstack;
  2586.     X
  2587.     Xstatic SIGRET
  2588.     Xto_sfgets()
  2589.     X{
  2590.     X    longjmp(SFGstack, 1);
  2591.     X}
  2592.     X
  2593.     Xint
  2594.     Xsockread(buf)
  2595.     Xchar *buf;
  2596.     X{
  2597.     X    int    esave, rz;
  2598.     X    char * ret;
  2599.     X    if (setjmp(SFGstack)) {
  2600.     X        (void) alarm(0);    /* reset alarm clock */
  2601.     X        (void) signal(SIGALRM, SIG_DFL);
  2602.     X        rd_fp->_flag |= _IOERR;    /* set stdio error */
  2603.     X#ifndef ETIMEDOUT
  2604.     X        errno = EPIPE;        /* USG doesn't have ETIMEDOUT */
  2605.     X#else
  2606.     X        errno = ETIMEDOUT;        /* connection timed out */
  2607.     X#endif
  2608.     X#ifdef SYSLOG
  2609.     X        syslog(LOG_ERR,"nntpxfer: read error on server socket: %m");
  2610.     X#else
  2611.     X        (void) perror("nntpxfer: read error on server socket");
  2612.     X#endif
  2613.     X        (void) close(server);
  2614.     X        exit(1);
  2615.     X    }
  2616.     X    (void) signal(SIGALRM, to_sfgets);
  2617.     X    (void) alarm(TIMEOUT);
  2618.     X    ret  = fgets(buf, BUFSIZ, rd_fp);
  2619.     X    esave = errno;
  2620.     X    (void) alarm(0);            /* reset alarm clock */
  2621.     X    (void) signal(SIGALRM, SIG_DFL);    /* reset SIGALRM */
  2622.     X    errno = esave;
  2623.     X    rz = strlen(buf);
  2624.     X    buf[rz-2] = '\0';
  2625.     X    if (ret  == (char * ) 0) {
  2626.     X#ifdef SYSLOG
  2627.     X            syslog(LOG_ERR,"nntpxfer: read error on server socket: %m");
  2628.     X#else
  2629.     X        (void) perror("nntpxfer: read error on server socket");
  2630.     X#endif
  2631.     X        (void) fclose(rd_fp);
  2632.     X        exit(1);
  2633.     X    }
  2634.     X    return(0);
  2635.     X}
  2636.     X
  2637.     Xsockwrite(buf)
  2638.     Xchar *buf;
  2639.     X    {
  2640.     X    register int sz;
  2641.     X    char buf2[BUFSIZ];
  2642.     X#ifdef DEBUG
  2643.     X    (void) printf(">>> %s\n", buf);
  2644.     X#endif
  2645.     X    (void) strcpy(buf2,buf);
  2646.     X    (void) strcat(buf2,"\r\n");
  2647.     X    sz = strlen(buf2);
  2648.     X    if (write(server,buf2,sz) != sz)
  2649.     X        {
  2650.     X#ifdef SYSLOG
  2651.     X        syslog(LOG_ERR,"nntpxfer: write error on server socket");
  2652.     X#else
  2653.     X        (void) printf("nntpxfer: write error on server socket\n");
  2654.     X#endif
  2655.     X        (void) close(server);
  2656.     X        exit(1);
  2657.     X        }
  2658.     X    }
  2659.     X
  2660.     Xint
  2661.     Xwewant(articleid)
  2662.     Xchar *articleid;
  2663.     X    {
  2664.     X#if defined(DBM) || defined(NDBM)
  2665.     X    datum k, d;
  2666.     X#else
  2667.     X    FILE *k;
  2668.     X    char *histfile();
  2669.     X    FILE *histfp;        /* USG history file */
  2670.     X    char line[BUFSIZ];
  2671.     X    int len;
  2672.     X#endif
  2673.     X    char id[BUFSIZ];
  2674.     X    char *p;
  2675.     X
  2676.     X    /* remove any case sensitivity */
  2677.     X    (void) strcpy(id, articleid);
  2678.     X    p = id;
  2679.     X#ifndef CNEWS
  2680.     X    while (*p)
  2681.     X        {
  2682.     X        if (isupper(*p))
  2683.     X            *p = tolower(*p);
  2684.     X        p++;
  2685.     X        }
  2686.     X#endif
  2687.     X#if defined(DBM) || defined(NDBM)
  2688.     X    k.dptr = id;
  2689.     X    k.dsize = strlen(articleid) + 1;
  2690.     X
  2691.     X#ifdef DBM
  2692.     X    d = fetch(k);
  2693.     X#else
  2694.     X     d = dbm_fetch(db, k);
  2695.     X#endif
  2696.     X    if (d.dptr)
  2697.     X        {
  2698.     X#ifdef DEBUG
  2699.     X        (void) printf("dup: '%s'\n", articleid);
  2700.     X#endif
  2701.     X        return(0);
  2702.     X        }
  2703.     X#ifdef DEBUG
  2704.     X    (void) printf("new: '%s'\n", articleid);
  2705.     X#endif
  2706.     X    return(1);
  2707.     X#else
  2708.     X    histfp = fopen(histfile(articleid), "r");
  2709.     X    if (histfp == NULL) 
  2710.     X        {
  2711.     X#ifdef DEBUG
  2712.     X        (void) printf("new: '%s'\n", articleid);
  2713.     X#endif
  2714.     X        return(1);
  2715.     X        }
  2716.     X    len = strlen(articleid);
  2717.     X    while (fgets(line, sizeof (line), histfp))
  2718.     X        if (!strncmp(articleid, line, len))
  2719.     X            break;
  2720.     X
  2721.     X    if (feof(histfp)) {
  2722.     X        (void) fclose(histfp);
  2723.     X#ifdef DEBUG
  2724.     X        (void) printf("new: '%s'\n", articleid);
  2725.     X#endif
  2726.     X        return (1);
  2727.     X    }
  2728.     X    (void) fclose(histfp);
  2729.     X#ifdef DEBUG
  2730.     X    (void) printf("dup: '%s' %s\n", articleid,line);
  2731.     X#endif
  2732.     X    return(0);
  2733.     X#endif
  2734.     X}
  2735.     X
  2736.     X#ifdef USGHIST
  2737.     X/*
  2738.     X** Generate the appropriate history subfile name
  2739.     X*/
  2740.     Xchar *
  2741.     Xhistfile(hline)
  2742.     Xchar *hline;
  2743.     X{
  2744.     X    char chr;    /* least significant digit of article number */
  2745.     X    static char subfile[BUFSIZ];
  2746.     X
  2747.     X    chr = findhfdigit(hline);
  2748.     X    sprintf(subfile, "%s.d/%c", HISTORY_FILE, chr);
  2749.     X    return subfile;
  2750.     X}
  2751.     X
  2752.     Xfindhfdigit(fn)
  2753.     Xchar *fn;
  2754.     X{
  2755.     X    register char *p;
  2756.     X    register int chr;
  2757.     X    extern char * index();
  2758.     X
  2759.     X    p = index(fn, '@');
  2760.     X    if (p != NULL && p > fn)
  2761.     X        chr = *(p - 1);
  2762.     X    else
  2763.     X        chr = '0';
  2764.     X    if (!isdigit(chr))
  2765.     X        chr = '0';
  2766.     X    return chr;
  2767.     X}
  2768.     X#endif
  2769.     Xchar *
  2770.     Xerrmsg(code)
  2771.     Xint code;
  2772.     X{
  2773.     X    extern int sys_nerr;
  2774.     X    extern char *sys_errlist[];
  2775.     X    static char ebuf[6+5+1];
  2776.     X
  2777.     X    if (code > sys_nerr || code < 0) {
  2778.     X        (void) sprintf(ebuf, "Error %d", code);
  2779.     X        return ebuf;
  2780.     X    } else
  2781.     X        return sys_errlist[code];
  2782.     X}
  2783.     X
  2784. SHAR_EOF
  2785. if test 12837 -ne "`wc -c < 'nntpxfer.c'`"
  2786. then
  2787.     echo shar: error transmitting "'nntpxfer.c'" '(should have been 12837 characters)'
  2788. fi
  2789. echo "Done with directory 'xfer'"
  2790. cd ..
  2791. fi
  2792. #    End of shell archive
  2793. exit 0
  2794.